并发字典中的valueFactory
本文关键字:valueFactory 字典 并发 | 更新日期: 2023-09-27 18:10:38
我正在写一个winform程序来测试c#并发字典,下面的类:
public class Class1
{
public int X = 10;
public Class1(int x)
{
X = x;
Debug.WriteLine("Class1 Created");
}
}
及以下按钮代码:
private void button1_Click(object sender, EventArgs e)
{
var dict = new ConcurrentDictionary<int, Class1>();
Func<Class1> valueFactory = () =>
{
Debug.WriteLine("Factory Called");
return new Class1(5);
};
var temp = dict.GetOrAdd(1, valueFactory());
Debug.WriteLine(temp.X);
temp.X = 20;
var temp2 = dict.GetOrAdd(1, valueFactory());
Debug.WriteLine(temp2.X);
}
我注意到valueFactory方法总是被执行,Class1构造函数被调用两次,即使在第一个GetorAdd方法之后键已经存在于字典中。
但是,如果我将Func定义更改为
Func<int, Class1> valueFactory = (k) =>
{
Debug.WriteLine("Factory Called");
return new Class1(5);
};
并像下面这样调用GetorAdd方法:
var temp = dict.GetOrAdd(1, valueFactory);
程序以期望的方式工作,因为它在第二次调用中没有调用Class1构造函数。我怀疑这是因为我传递了一个委托valueFactory而不是函数调用valueFactory()
到GetorAdd方法。我想知道是否有一个详细的解释正在发生的事情,我也不明白为什么我不能不传递valueFactory作为委托,如果我的Func定义是Func<int, Class1
以外的任何东西(与字典的定义相同)
谢谢。
当你这样做的时候:
var temp = dict.GetOrAdd(1, valueFactory());
...
var temp2 = dict.GetOrAdd(1, valueFactory());
实际上是在调用dict.GetOrAdd()之前调用valueFactory
。所以它每次都被调用是正常的。当然,第二次调用valueFactory()
返回的Class1
的新实例最终是没有用的,但是它还是被创建了。
相反,当你这样做时:
var temp = dict.GetOrAdd(1, valueFactory);
...
var temp2 = dict.GetOrAdd(1, valueFactory);
…您实际上使用的是GetOrAdd方法的不同重载,其中您将引用传递给委托valueFactory
而无需自己调用它。然后,GetOrAdd()
方法根据是否在字典中找到键来决定是否需要调用valueFactory
。
ConcurrentDictionary最后。GetOrAdd Method (TKey, Func) doc:
使用指定的函数为
ConcurrentDictionary<TKey, TValue>
添加一个键/值对,如果键不存在
在这种情况下,它不需要第二次调用它,因为它在第二次调用GetOrAdd()
时找到了键。
然而,请注意,将valueFactory
作为委托传递给GetOrAdd
并不能保证它不会被调用两次。在多线程场景中尤其如此。注意ConcurrentDictionary的文档。GetOrAdd方法(TKey, Func)也表示:
如果在不同的线程上同时调用
GetOrAdd
,addValueFactory
可能会被多次调用,但它的键/值对可能不会在每次调用时都被添加到字典中。