C# 这本ConcurrentDictionary&x2B;懒惰<;任务<;T>&燃气轮机;代码工作?

C# 这本ConcurrentDictionary&x2B;懒惰<;任务<;T>&燃气轮机;代码工作?,c#,.net,asynchronous,concurrentdictionary,C#,.net,Asynchronous,Concurrentdictionary,有人说,.NET/.NET内核的ConcurrentDictionaryGetOrAdd方法在使用Func委托计算要插入到字典中的值时(如果键不存在)不是线程安全的 我相信,当使用concurrentdirectionary的GetOrAdd方法的工厂方法时,如果在“同一时间”发生多个请求,则可以“同时/快速连续”多次调用它。这可能是浪费,尤其是如果通话“昂贵”。(@panagiotis kanavos比我解释得更好)。有了这个假设,我很难理解我编写的一些示例代码是如何工作的 我已经试过了,但我

有人说,.NET/.NET内核的
ConcurrentDictionary
GetOrAdd
方法在使用
Func
委托计算要插入到字典中的值时(如果键不存在)不是线程安全的

我相信,当使用
concurrentdirectionary
GetOrAdd
方法的工厂方法时,如果在“同一时间”发生多个请求,则可以“同时/快速连续”多次调用它。这可能是浪费,尤其是如果通话“昂贵”。(@panagiotis kanavos比我解释得更好)。有了这个假设,我很难理解我编写的一些示例代码是如何工作的

我已经试过了,但我一直在努力理解它是如何工作的

我读过的一个常见建议/想法是在
ConcurrentDictionary
中有一个
Lazy
值。其思想是,
Lazy
阻止其他调用执行底层方法

规范中负责起重作业的主要部分如下:

    public static async Task<DateTime> GetDateFromCache()
    {
        var result = await _cache.GetOrAdd("someDateTime", new Lazy<Task<DateTime>>(async () => 
        {
            // NOTE: i've made this method take 2 seconds to run, each time it's called.
            var someData = await GetDataFromSomeExternalDependency();
            
            return DateTime.UtcNow;
            
        })).Value;
        
        return result;
    }
公共静态异步任务GetDateFromCache() { var result=await\u cache.GetOrAdd(“someDateTime”,new Lazy(async()=> { //注意:我已经让这个方法每次调用都需要2秒的时间来运行。 var someData=await GetDataFromSomeExternalDependency(); return DateTime.UtcNow; })).价值; 返回结果; } 我是这样读的:

  • 检查字典中是否存在
    someDateTime
  • 如果是,请将其退回。 因为我假设(上面)键/值中的值是一个
    惰性的

    是的,确实如此

    等待者每次都会打电话。如果每次调用一个wait(因为Lazy保护其他调用者不同时调用所有调用者),那么我认为每次独立调用的结果将是不同的DateTime


    wait不是一个调用,它更像是“当结果可用时继续执行”。访问
    Lazy.Value
    将创建任务,这将启动对
    GetDataFromSomeExternalDependency
    的调用,该调用最终返回日期时间。你可以等待任务,不管你想等待多少次,都可以得到相同的结果。

    ConcurrentDictionary GetOrAdd方法不是线程安全的,因为这些答案根本不是这样说的。他们说的是,工厂方法虽然是线程安全的,但如果同时调用多次,就不能保证只产生一个结果。如果发生这种情况,将只使用wait每次调用的
    值中的一个。任务是已激活的承诺,而不是函数指针。调用
    await
    不会运行承诺,而是等待它产生结果。多次调用
    await
    将不会再次运行任务,它将返回
    Lazy
    的第一个结果,对于Lazy求值,实际上并不需要它-当您调用
    GetDateFromCache
    时,您现在就想要答案
    ConcurrentDictionary
    没有异步工厂方法,因此使用了
    Lazy
    将异步工厂方法转换为同步对象。本质上,它同步可能的并发工厂调用
    (因为延迟保护其他调用方不同时进行所有调用)。。。每次独立调用。
    Lazy确保只成功调用一次(默认情况下,确保在给定时间点只进行一次尝试)。第一次运行成功,因此后续每次调用都不会发生。请求完成任务的
    结果
    没有任何作用。它只是再次提供相同的值。如果它没有完成(在飞机上),它只是阻塞,直到它准备好。这与我的观点是一致的。