设想

假设我们有:

var dictionary = new ConcurrentDictionary<string, Lazy<Heavy>>();

实例化 Heavy 非常消耗资源。让我们考虑一下这段代码:
return dictionary.GetOrAdd("key", key =>
{
    return new Lazy<Heavy>(() =>
    {
        return Instantiate();
    });
}).Value;
Instantiate() 方法当然会返回一个 Heavy 类型的实例。

问题

对于给定的键,是否 100% 保证方法 Instantiate() 最多将被调用一次

来源

有人声称拥有多个线程,我们只能创建 Lazy<Heavy> 的多个实例,这非常便宜。实际的方法 Instantiate() 最多会被调用一次。
  • https://social.msdn.microsoft.com/Forums/en-US/e350f7d0-b860-482e-9b84-8dba12267d25/failure-of-lock-with-tpl?forum=parallelextensions
  • http://reedcopsey.com/2011/01/16/concurrentdictionarytkeytvalue-used-with-lazyt/

  • 我个人的印象是,这是错误的。真相是什么?

    最佳答案

    Instantiate 确实只会执行一次。 GetOrAdd 的文档说:



    这意味着:即使 addValueFactory 多次运行 - 只有一个返回值实际上会被添加到字典中并从 GetOrAdd 调用返回。因此,如果两个线程同时使用相同的键调用 GetOrAdd - 创建了 2 个 Lazy<Heavy> 实例,但只有 1 个实例被添加到字典中并从两个 GetOrAdd 调用返回,另一个将被丢弃(因此,即使工厂已经运行 -这并不意味着该工厂提供的值是最终从 GetOrAdd 返回的值)。因为你在 .Value 的结果上调用 GetOrAdd - 你总是在 Lazy<Heavy> 的单个实例上调用它,所以 Instantiate 总是最多运行一次。

    关于c# - ConcurrentDictionary + Lazy -- 实例化只会发生一次吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47489211/

    10-11 23:09
    查看更多