c# - ConcurrentDictionary.GetOrAdd() 是否保证每个键只调用一次 valueFactoryMethod?

标签 c# .net multithreading parallel-processing

问题:我需要实现对象缓存。缓存需要是线程安全的并且需要按需填充值(延迟加载)。这些值是通过 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/

相关文章:

c# - 将枚举与列表进行比较<int>

c# - 使用异步时未处理 SqlConnection

java - 将锁转移到 Java 中的衍生线程

c++ - 在 C++ 中,如何在 X 秒后重置类中的变量?

ruby - Ruby Thread 的派生类?

c# - 异常管理错误

c# - 启用 MSI 时连接到 SQL

c# - IQueryable for entities .Where(属性在本地数组中)

.net - HttpResult(HttpStatusCode.NoContent) 创建响应 "OK"

c# - Azure WebJobs 未找到函数