我假设此代码存在并发问题:
const string CacheKey = "CacheKey";
static string GetCachedData()
{
string expensiveString =null;
if (MemoryCache.Default.Contains(CacheKey))
{
expensiveString = MemoryCache.Default[CacheKey] as string;
}
else
{
CacheItemPolicy cip = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(20))
};
expensiveString = SomeHeavyAndExpensiveCalculation();
MemoryCache.Default.Set(CacheKey, expensiveString, cip);
}
return expensiveString;
}
Run Code Online (Sandbox Code Playgroud)
并发问题的原因是多个线程可以获取空键,然后尝试将数据插入缓存.
什么是最简洁,最干净的方法来使这个代码并发证明?我喜欢在缓存相关代码中遵循一个好的模式.链接到在线文章将是一个很大的帮助.
更新:
我根据@Scott Chamberlain的回答提出了这个代码.任何人都可以找到任何性能或并发问题吗?如果这样做,它将节省许多代码和错误.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Caching;
namespace CachePoc
{
class Program
{
static object everoneUseThisLockObject4CacheXYZ = new object();
const string CacheXYZ = "CacheXYZ";
static …Run Code Online (Sandbox Code Playgroud) 我使用MemoryCache类创建了一个缓存.我添加了一些项目,但是当我需要重新加载缓存时,我想首先清除它.最快的方法是什么?我应该遍历所有项目并一次删除一个项目还是有更好的方法?
我正在使用应用程序中的.NET 4.0 MemoryCache类并尝试限制最大缓存大小,但在我的测试中,似乎缓存实际上并未遵守限制.
我使用的设置,根据MSDN,应该限制缓存大小:
- CacheMemoryLimitMegabytes:对象实例可以增长到的最大内存大小(以兆字节为单位)."
- PhysicalMemoryLimitPercentage: "缓存可以使用的物理内存百分比,表示为1到100之间的整数值.默认值为零,表示 MemoryCache实例根据安装在内存中的内存量管理自己的内存 1电脑." 1.这不完全正确 - 忽略任何低于4的值并替换为4.
我理解这些值是近似值而不是硬限制,因为清除缓存的线程每隔x秒触发一次,并且还取决于轮询间隔和其他未记录的变量.然而,即使考虑到这些差异,在将测试应用程序中的CacheMemoryLimitMegabytes 和PhysicalMemoryLimitPercentage一起或单独设置后,当第一项从缓存中逐出时,我看到了非常不一致的缓存大小.为了确保我每次测试10次并计算出平均值.
这些是在具有3GB RAM的32位Windows 7 PC上测试以下示例代码的结果.在每次测试第一次调用CacheItemRemoved()之后获取缓存的大小.(我知道缓存的实际大小将大于此)
MemLimitMB MemLimitPct AVG Cache MB on first expiry
1 NA 84
2 NA 84
3 NA 84
6 NA 84
NA 1 84
NA 4 84
NA 10 84
10 20 81
10 30 81
10 39 82
10 40 79
10 49 146
10 50 152
10 60 …Run Code Online (Sandbox Code Playgroud) 首先让我把它扔出去,我知道下面的代码不是线程安全的(更正:可能).我正在努力的是找到一个实现,并且我实际上可以在测试中失败.我现在正在重构一个大型WCF项目,它需要一些(大部分)静态数据缓存并从SQL数据库中填充.它需要每天至少过期和"刷新"一次,这就是我使用MemoryCache的原因.
我知道下面的代码不应该是线程安全的,但我不能让它在繁重的负载下失败,并且使谷歌搜索显示两种方式的实现变得复杂(有和没有锁结合辩论,无论它们是否必要.
在多线程环境中具有MemoryCache知识的人可以让我明确地知道我是否需要在适当的地方锁定,以便在检索/重新填充期间不会抛出删除调用(很少被调用但是它的要求).
public class MemoryCacheService : IMemoryCacheService
{
private const string PunctuationMapCacheKey = "punctuationMaps";
private static readonly ObjectCache Cache;
private readonly IAdoNet _adoNet;
static MemoryCacheService()
{
Cache = MemoryCache.Default;
}
public MemoryCacheService(IAdoNet adoNet)
{
_adoNet = adoNet;
}
public void ClearPunctuationMaps()
{
Cache.Remove(PunctuationMapCacheKey);
}
public IEnumerable GetPunctuationMaps()
{
if (Cache.Contains(PunctuationMapCacheKey))
{
return (IEnumerable) Cache.Get(PunctuationMapCacheKey);
}
var punctuationMaps = GetPunctuationMappings();
if (punctuationMaps == null)
{
throw new ApplicationException("Unable to retrieve punctuation mappings from the database.");
}
if (punctuationMaps.Cast<IPunctuationMapDto>().Any(p => p.UntaggedValue …Run Code Online (Sandbox Code Playgroud) 我想使用System.Runtime.Caching命名空间向我的应用程序添加缓存功能,并且可能希望在几个地方和不同的上下文中使用缓存.为此,我想使用几个MemoryCache实例.
但是,我在这里看到不鼓励使用多个MemoryCache实例:
MemoryCache不是单例,但是您应该只创建一些或者可能只创建一个MemoryCache实例,缓存项目的代码应该使用这些实例.
多个MemoryCache实例将如何影响我的应用程序?我发现这种奇怪,因为在我看来,在应用程序中使用多个缓存是一种非常常见的情况.
编辑:更具体地说,我有一个类应该为每个实例保留一个缓存.我应该避免使用MemoryCache并寻找不同的缓存解决方案吗?MemoryCache在这种情况下使用是否被认为是坏的,如果是这样,为什么?
在ASP.NET MVC项目中,我们有几个数据实例需要大量资源和时间来构建.我们想要缓存它们.
MemoryCache提供一定程度的线程安全性但不足以避免并行运行多个构建代码实例.这是一个例子:
var data = cache["key"];
if(data == null)
{
data = buildDataUsingGoodAmountOfResources();
cache["key"] = data;
}
Run Code Online (Sandbox Code Playgroud)
正如您在繁忙的网站上看到的那样,数百个线程可以同时进入if语句,直到构建数据并使构建操作更慢,不必要地消耗服务器资源.
AddOrGetExisting在MemoryCache中有一个原子实现,但它错误地需要"值来设置"而不是"代码来检索要设置的值",我认为这使得给定的方法几乎完全没用.
我们一直在MemoryCache周围使用我们自己的ad-hoc脚手架来实现它,但它需要明确的locks.使用每个条目的锁定对象很麻烦,我们通常会通过共享远离理想的锁定对象来逃避.这让我觉得避免这种惯例的理由可能是故意的.
所以我有两个问题:
不lock建立代码是一种更好的做法吗?(对于一个人来说,这可能已被证明更具响应性,我想知道)
对于这样的锁,实现MemoryCache的每个条目锁定的正确方法是什么?使用key字符串作为锁定对象的强烈冲动在".NET锁定101"中被忽略.
我有一个使用新的.NET 4 System.Runtime.Caching MemoryCache的MVC 3应用程序的问题.我注意到在看似无法预测的时间之后,它会停止缓存,并且表现得像空的一样.考虑一下我直接从ASP.NET MVC中的测试View获取的代码:
MemoryCache.Default.Set("myname","fred", new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0,5,0) });
Response.Write(MemoryCache.Default["myname"]);
Run Code Online (Sandbox Code Playgroud)
当它工作时,可预测的"fred"被打印出来.但是,当问题开始出现时,尽管如此Set(),值为MemoryCache.Default["myname"]null.我可以通过在线上设置断点Response.Write()并使用立即窗口直接设置和读取缓存来证明这一点- 它不会设置它并保持为空!让它再次运行的唯一方法是使AppDomain回收.
有趣的是,当应用程序正常工作时,我可以通过打破Response.Write()线路并运行来激发问题MemoryCache.Default.Dispose().之后,MemoryCache.Default本身不为null(为什么会这样?),但不保存任何设置.它不会导致任何错误,但不会保存任何内容.
任何人都可以验证并解释吗?我相信我已经发现,当应用程序停止工作时,有些东西是Disposing MemoryCache.Default,但这不是我!
UPDATE
好吧,我现在厌倦了这个问题!CLRProfiler似乎不适用于MVC 3.SciTech的CLR工具很好 - RedGate ANTS也是如此.但他们告诉我的只是MemoryCache对象被某些东西处理掉了!我还证明了(通过时间戳打印)我的页面上应该被缓存的部分视图(由OutputCacheAttribute指定)在几分钟后停止缓存 - 它会在每次调用页面时开始刷新.为了澄清环境,我直接在运行Win 7 Ultimate的开发工作站上的IIS 7.5服务器上运行.上面提到的内存工具表明我在播放对象方面只使用了大约9mb的内存.
无奈之下,我已经改变了我的缓存代码,首先搜索环境HttpContext以挂钩并使用其缓存功能(如果有的话).早期测试显示这是可靠的,但感觉就像一个讨厌的黑客.
我觉得MemoryCache和OutputCache不能保证与MVC 3一起工作......
我MemoryCache在ASP.NET中使用它并且运行良好.我有一个缓存了一个小时的对象,以防止从存储库中获取新的数据.
我可以看到缓存在调试中工作,但是一旦部署到服务器,在第一次调用并且对象被缓存后,后续调用大约是1/5的时间.
但是我注意到每个新的客户端呼叫(仍然在那个1小时的窗口内 - 事实上只是一分钟或者之后的两分钟)似乎第一次调用我的服务(即进行缓存)几乎和原来一样长在缓存数据之前调用.
这让我开始怀疑 - 是MemoryCache特定于会话的,并且每个进行调用的新客户端都存储它自己的缓存,或者是否有其他事情导致第一次调用花了这么长时间甚至在我知道数据已被缓存之后?
遗憾的是,MemoryCache.Set的MSDN文档没有明确说明它是否是线程安全的.
是否可以安全地使用.Get()并且.Set()没有显式锁定的几个线程?
memorycache ×10
c# ×7
.net ×6
caching ×5
.net-4.0 ×2
asp.net ×2
asp.net-mvc ×1
memory ×1
wcf ×1