问题:我需要实现对象缓存。缓存需要是线程安全的并且需要按需填充值(延迟加载)。这些值是通过 Key 的 Web 服务检索的(操作缓慢)。所以我决定使用 ConcurrentDictionary
及其 GetOrAdd()具有值工厂方法的方法假设操作是原子的和同步的。不幸的是,我在 MSDN 文章中发现了以下声明:How to: Add and Remove Items from a ConcurrentDictionary :
Also, although all methods of ConcurrentDictionary are thread-safe, not all methods are atomic, specifically GetOrAdd and AddOrUpdate. The user delegate that is passed to these methods is invoked outside of the dictionary's internal lock.
嗯,这很不幸,但仍然没有完全回答我的答案。
问题:每个键只调用一次值工厂吗?在我的具体情况下:是否有可能正在寻找相同键的多个线程针对相同的值对 Web 服务产生多个请求?
最佳答案
正如其他人已经指出的那样,valueFactory
可以被多次调用。有一个缓解此问题的通用解决方案 - 让您的 valueFactory
返回 Lazy<T>
实例。尽管可能会创建多个惰性实例,但实际的 T
仅当您访问 Lazy<T>.Value
时才会创建值属性(property)。
具体来说:
// Lazy instance may be created multiple times, but only one will actually be used.
// GetObjectFromRemoteServer will not be called here.
var lazyObject = dict.GetOrAdd("key", key => new Lazy<MyObject>(() => GetObjectFromRemoteServer()));
// Only here GetObjectFromRemoteServer() will be called.
// The next calls will not go to the server
var myObject = lazyObject.Value;
此方法在 Reed Copsey's blog post 中有进一步解释。
关于c# - ConcurrentDictionary.GetOrAdd() 是否保证每个键只调用一次 valueFactoryMethod?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31637394/