以异步方式在并发字典中调用valuefactory

Sea*_*ean 5 c# asynchronous concurrentdictionary

我是C#ConcurrentDictionary类的新手,我想知道如何GetOrAdd以异步方式在方法中使用valueFactory .

public class Class1
{
    public int X = 10;

    public Class1(int x)
    {
        X = x;
        Debug.WriteLine("Class1 Created");
    }
}
Run Code Online (Sandbox Code Playgroud)

在WinForm按钮中测试代码逻辑:

private async void button1_Click(object sender, EventArgs e)
{
    var asyncDict = new ConcurrentDictionary<int, Task<Class1>>();

    Func<int, Task<Class1>> valueFactoryAsync = async (k) => new Class1(await Task.Run(async () =>
    {
        await Task.Delay(2000);
        Debug.WriteLine("Async Factory Called");
        return 5;
    }));

    var temp = await(asyncDict.GetOrAdd(1, valueFactoryAsync)).ConfigureAwait(false);
    Debug.WriteLine(temp.X);
    temp.X = 20;
    var temp2 = await (asyncDict.GetOrAdd(1, valueFactoryAsync)).ConfigureAwait(false);
    Debug.WriteLine(temp2.X);
}
Run Code Online (Sandbox Code Playgroud)

当第二次调用GetOrAdd方法时,它从并发字典返回一个Task.然后我在任务上调用await, var temp2 = await (asyncDict.GetOrAdd(1,valueFactoryAsync)).ConfigureAwait(false); 似乎没有再次调用底层的Task(或async方法)并返回一个新的Class1对象.它是否只返回了第一次调用中生成的Class1对象?你能告诉引擎盖下发生了什么吗?

sha*_*y__ 1

asyncDict.GetOrAdd(1,valueFactoryAsync)是的,当您第二次调用时,您会得到相同的实例。为什么这让你感到惊讶?您提供了与第一次相同的密钥。

幕后发生了什么?

var temp = await(asyncDict.GetOrAdd(1, valueFactoryAsync)).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

当调用该行时,字典中没有 key=1 的项,因此valueFactoryAsync被调用,返回一个 Status=Created 的任务,并且该任务被添加到字典中。这部分就这样了Add。现在开始这Get部分,您将返回新的准备运行的任务。你其实正在等待此任务 ( var temp = await (...)),因此任务开始,并且在该任务完成之前,您的下一行代码不会执行。我希望剩下的事情从这里开始就非常简单了 - 下次你打电话时await (asyncDict.GetOrAdd(1, valueFactoryAsync))-temp2字典中已经有这个键的项目 - 一个已完成的任务,这就是你得到的任务。请注意,即使您没有等待第一次调用,字典仍然会填充Created任务,并且在第二次调用时您仍然会得到相同的任务(因此Class1如果您await/.Result它,则会得到相同的实例)