调用GetOrAdd时如何将异步方法的结果存储在.NET ConcurrentDictionary中? [英] How to store the result of an async method in a .NET ConcurrentDictionary when calling GetOrAdd?
问题描述
我有一个private ConcurrentDictionary
,它是一些数据库密钥的简单查找表.
I have a private ConcurrentDictionary
that is a simple lookup table of some DB keys.
我试图利用ConcurrentDictionary
,以便仅在同时向同一行代码发出2个以上请求时才对数据库执行一次调用. (这就是为什么我使用ConcurrentDictionary
的原因.)
I'm trying to leverage the ConcurrentDictionary
so that it will only do one call to the db when 2+ requests to the same line of code, are made at the same time. (Which is why i'm using a ConcurrentDictionary
.)
请问我该怎么做?
这是我尝试要做的..但是我认为它是将Task
存储在字典中……而不是任务的结果. ..
This is what I was trying to do .. but I think it's storing the Task
in the dictionary ... not the result of the task....
private readonly ConcurrentDictionary<string, Task<int>> _myKeys = new ConcurrentDictionary<string, Task<int>>();
...
private async Task<int> DoStuffAsync(string key)
{
// do stuff here.
return await _myKeys.GetOrAdd(key,
async k => await _db.GetId(k)
.ConfigureAwait(false))
.ConfigureAwait(false);
}
有什么想法吗?
注意我的方法签名和返回的内容.返回一个int
而不是一个Task<int>
更好,然后以某种方式将我的数据库调用重构为仍然是异步..但更好..
Notice my method signature and what I'm returning. Is it better to return an int
and not a Task<int>
and then somehow refactor my db call to still be async .. but .. better?
推荐答案
GetOrAdd
不保证当同时从多个线程以相同的值调用该委托时,该委托仅被调用一次:
GetOrAdd
does not guarantee that the delegate will be called only once when it's called from multiple threads at the same time with the same value:
如果您同时在不同的线程上调用GetOrAdd,则可能会多次调用 addValueFactory ,但是可能不会为每个调用将其键/值对添加到字典中.
If you call GetOrAdd simultaneously on different threads, addValueFactory may be called multiple times, but its key/value pair might not be added to the dictionary for every call.
这也可以在实现:
TValue resultingValue;
if (TryGetValue(key, out resultingValue))
{
return resultingValue;
}
TryAddInternal(key, valueFactory(key), false, true, out resultingValue);
return resultingValue;
因此,要完成与GetOrAdd()
一样好的工作,您可以做类似的事情(省略输入检查):
So, to do about as good a job as GetOrAdd()
, you can do something like (input checking omitted):
public static async Task<TValue> GetOrAddAsync<TKey, TValue>(
this ConcurrentDictionary<TKey, TValue> dictionary,
TKey key, Func<TKey, Task<TValue>> valueFactory)
{
TValue resultingValue;
if (dictionary.TryGetValue(key, out resultingValue))
{
return resultingValue;
}
return dictionary.GetOrAdd(key, await valueFactory(key));
}
如果不要求同时调用两次代表只是一项性能优化,那么这就足够了.
If the requirement to not call the delegate twice at the same time is just a performance optimization, this should be sufficient.
如果代码正确性需要它,那么即使GetOrAdd
也是不够的,您将需要使用其他同步.
If it's required for correctness of your code, then even GetOrAdd
is not sufficient and you will need to use additional synchronization.
这篇关于调用GetOrAdd时如何将异步方法的结果存储在.NET ConcurrentDictionary中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!