我是C#的for($x=1;$x<100;$x++) {
if($x %4 != 0 && $x != 1) continue;
else enter code here
}
类的新手,我想知道如何以异步方式在ConcurrentDictionary
方法中使用valueFactory。
GetOrAdd
在WinForm按钮中测试代码逻辑:
public class Class1
{
public int X = 10;
public Class1(int x)
{
X = x;
Debug.WriteLine("Class1 Created");
}
}
第二次调用GetOrAdd方法时,它会从并发字典中返回一个Task。然后我打电话给等待任务,
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);
}
似乎没有再次调用底层的Task(或async方法)并返回一个新的Class1对象。它是否只返回了第一次调用中生成的Class1对象?
你能告诉引擎盖下发生了什么吗?
答案 0 :(得分:1)
是的,当您第二次拨打nw
时,您会获得相同的实例。为什么这让你感到惊讶?您提供了与第一次相同的密钥。
引擎盖下发生了什么?
asyncDict.GetOrAdd(1,valueFactoryAsync)
当调用此行时,字典中没有key = 1的项,因此调用var temp = await(asyncDict.GetOrAdd(1, valueFactoryAsync)).ConfigureAwait(false);
,返回Status = Created的Task,并将此Task添加到字典中。这是valueFactoryAsync
部分的结果。现在开始Add
部分,您将获得新的准备运行任务。您实际上等待此任务(Get
),因此任务开始,您的下一行代码将不会执行,直到此任务完成。我希望其余部分从这里开始非常简单 - 下次你致电var temp = await (...)
- await (asyncDict.GetOrAdd(1, valueFactoryAsync))
时 - 字典中已经有一个关于此密钥的项目 - 一个已完成的任务,以及那个你得到的任务。请注意,即使您没有等待第一次调用,字典仍然会填充temp2
任务,而在第二次调用时,您仍然可以获得相同的任务(因此{{1}如果你Created
/ Class1
,那么实例
答案 1 :(得分:0)
GetOrAdd
已经解释了很多。我想让您了解ConcurrentDictionary<TKey, Lazy<TValue>>
可以为同一个键多次调用值工厂这一事实。你好像不想要那样。要避免这种情况的标准模式是使用TValue = Task<Class1>
。在这里,ConcurrentDictionary
。这样,只会产生一项任务。
public interface IContextProvider {
IHttpContextAccessor GetContext();
}
完全没有意识到任务并等待着。