常见缓存习语的线程影响

时间:2011-08-20 15:08:40

标签: c# multithreading caching

一种常见的缓存习惯用法是检查缓存中是否存在项目,检索是否存在,否则创建。

这是否会创建一个条件,如果在注释位置发生从Thread 1Thread 2的上下文切换,则当上下文切换回{{{}时,可能会立即覆盖添加到缓存的值。 1}}发生?缺点是Thread 1现在已被调用两次以计算相同的缓存项。这只是这个简单缓存实现的可接受的“次要”后果。是否通常不使用关键部分,因为这会增加所有calculateFooBar()方法的开销?

编辑:_cache是​​对共享数据缓存的引用(例如ASP.NET数据缓存)。

GetOrCreate

3 个答案:

答案 0 :(得分:1)

一切都取决于这个_cache变量是什么:它的类型和范围。如果它是静态变量而不是线程安全的,例如Dictionary<TKey, TValue>,则需要使用lock来同步对它的访问。在.NET 4.0中,您使用ConcurrentDictionary<TKey, TValue>类型,以线程安全的方式实现类似的功能。你的代码很好,但没有lock,不能保证在很短的时间内对同一个密钥不会发生两次计算。

您可以查看following blog post以获得此模式的一个很好的实现。此外,如果您使用的是.NET 4.0,则可以使用新的System.Runtime.Caching程序集。

答案 1 :(得分:1)

如果您的程序正常工作,即使您有该对象的两个实例,并且只有资源分配时间&amp;内存是你关注的我不会打扰添加锁。从长远来看,线程同步可能更昂贵。

ConcurrentDictionary&LT;&GT;对于这样的“nolock”容器来说,这将是一个不错的选择,正如其他人已经提到的那样。

答案 2 :(得分:1)

我们在几个场景中使用了一些自定义缓存......新的Concurrent * - .NET 4中的集合非常适合这种命令......

如果foobarsConcurrentDictionary<string, FooBar>,您可以执行以下操作:

return foobars.GetOrAdd (key, (k) => calculateFooBar() );

此代码将替换您的整个样本方法GetOrCreate

有关更多信息,请参阅http://geekswithblogs.net/BlackRabbitCoder/archive/2011/02/17/c.net-little-wonders-the-concurrentdictionary.aspx