ConcurrentDictionary + Lazy - 实例化只会发生一次吗?

Pat*_*ski 4 c# concurrency .net-core

脚本

假设我们有:

var dictionary = new ConcurrentDictionary<string, Lazy<Heavy>>();
Run Code Online (Sandbox Code Playgroud)

实例化Heavy非常耗费资源.我们考虑一下这段代码:

return dictionary.GetOrAdd("key", key => 
{
    return new Lazy<Heavy>(() =>
    {
        return Instantiate();
    });
}).Value;
Run Code Online (Sandbox Code Playgroud)

该方法Instantiate()当然返回一个类型的实例Heavy.

对于给定的密钥,是否100%保证该方法最多Instantiate()只能被调用一次

来源

有些人声称拥有多个线程,我们只能创建多个实例Lazy<Heavy>,这非常便宜.实际方法Instantiate()最多只能调用一次.

我个人有一种印象,认为这是错误的.真相是什么?

Evk*_*Evk 6

Instantiate确实只会执行一次.文件GetOrAdd说:

如果在不同的线程上同时调用GetOrAdd,可能会多次调用addValueFactory,但是对于每个调用,它的键/值对可能不会添加到字典中.

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