c# - 这个 ConcurrentDictionary + Lazy<Task<T>> 代码是如何工作的?

标签 c# .net asynchronous concurrentdictionary

various posts/answers也就是说 .NET/.NET Core 的 ConcurrentDictionary GetOrAddFunc 时,方法不是线程安全的如果键不存在,则委托(delegate)用于计算要插入字典的值。
我相信在使用 ConcurrentDictionary 的工厂方法时的 GetOrAdd方法,如果“同时”发生多个请求,则可以“同时/非常快速地连续”多次调用它。这可能会很浪费,尤其是在通话“昂贵”的情况下。 (@panagiotis-kanavos 比我更好地解释了这一点)。有了这个假设,我很难理解我制作的一些示例代码似乎是如何工作的。
我已经 created a working sample on .NET Fiddle但我一直在试图了解它是如何工作的。
我读过的一个常见的推荐建议/想法是拥有一个 Lazy<Task<T>> ConcurrentDictionary 中的值.这个想法是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;
    }
我是这样读的:
  • 检查是否 someDateTime键存在于字典中。
  • 如果是,请返回。 <-- 这是一个线程安全的原子操作。好极了!
  • 如果没有,那么我们开始......
  • 创建一个 Lazy<Task<DateTime>> 的实例(基本上是即时的)
  • 返回 Lazy实例。 (到目前为止,尚未调用实际的“昂贵”操作。)
  • 现在获取 Value ,这是一个 Task<DateTime> .
  • 现在 await这个任务 .. 最终完成了“昂贵”的调用。它等待 2 秒 .. 然后返回结果(某个时间点)。

  • 现在这就是我错的地方。因为我假设(以上)键/值中的值是 Lazy<Task<DateTime>> ...其中await每次都会打电话。如果await被调用,一次一个(因为 Lazy 保护其他调用者免于同时调用)然后我会认为结果会有所不同 DateTime每个独立的调用。
    那么有人可以解释一下我的想法错在哪里吗?
    (请参阅 .NET Fiddler 中的完整运行代码)。

    最佳答案

    Because I'm assuming (above) that the value in the key/value is a Lazy<Task<DateTime>>


    是的,这是真的。

    which the await would call each time. If the await is called, one at a time (because the Lazy protects other callers from all calling at the same time) then I would have though that the result would a different DateTime with each independent call.


    await 不是调用,它更像是“在结果可用时继续执行”。访问 Lazy.Value将创建任务,这将启动对 GetDataFromSomeExternalDependency 的调用。最终返回日期时间。您可以多次等待任务并获得相同的结果。

    关于c# - 这个 ConcurrentDictionary + Lazy<Task<T>> 代码是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65679538/

    相关文章:

    c# - 在 xamarin.forms 中使用 fontawesome(仅限 iOS 和 Android)

    c# - 从 Web 应用程序中检索原始用户身份

    c# - WinForms 中单选按钮列表的第三方控件?

    c# - 为什么 IPEndPoint 将 Int64 和 Int32 作为参数?

    .net - LINQ-to-SQL 按名称动态使用表

    c# - 跨 .NET 语言性能

    java - 服务器崩溃/关闭后恢复 Async ThreadPoolTask​​executor

    javascript - 使用 fetch 获取页面设置

    c# - 隐藏用于 editText 焦点/触摸的软键盘

    带有异步任务的 Android