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对象?你能告诉引擎盖下发生了什么吗?
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它,则会得到相同的实例)