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

时间:2015-09-02 00:19:39

标签: c# asynchronous concurrentdictionary

我是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对象? 你能告诉引擎盖下发生了什么吗?

2 个答案:

答案 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(); } 完全没有意识到任务并等待着。