调用GetOrAdd时如何将异步方法的结果存储在.NET ConcurrentDictionary中? [英] How to store the result of an async method in a .NET ConcurrentDictionary when calling GetOrAdd?

查看:104
本文介绍了调用GetOrAdd时如何将异步方法的结果存储在.NET ConcurrentDictionary中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆