有various posts/answers也就是说 .NET/.NET Core 的 ConcurrentDictionary
GetOrAdd
当 Func
时,方法不是线程安全的如果键不存在,则委托(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/