如果我有一个
ConcurrentDictionary
实例,那么使用 Count
属性还是 LINQ 的 Any()
有关系吗?我宁愿写 dict.Any()
而不是 dict.Count > 0
,因为我认为 Any()
更具描述性。
我只关心正确性,而不关心性能。用例是
void process()
{
if (concurrentDictionary.Count <= 0) // or !Any() ?
return; // dictionary is empty, nothing to do
// ...
}
问题 IEnumerable Linq 方法线程安全吗? 解决了这样一个事实:如果没有特定的锁来保护集合,LINQ 查询上的 IEnumerable 方法就不是线程安全的。
您可以查看ConcurrentDictionary的参考代码,发现枚举器不提供线程安全快照。 ConcurrentDictionary.GetEnumerator 的附加 MSDN 文档指出:
从字典返回的枚举器可以安全地与字典的读取和写入同时使用,但它并不代表字典的即时快照。通过枚举器暴露的内容可能包含调用 GetEnumerator 后对字典所做的修改
Count 属性对字典进行完全锁定并返回一致的结果。
因此,取决于您是否想锁定字典来运行
Any()
,检查Count > 0
可能会更干净。
您必须对它们进行基准测试,因为
Any()
类似于
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return true;
}
}
return false;
所以它需要枚举,对于
ConcurrentDictionary
来说是很复杂的东西,但即使是Count
的ConcurrentDictionary
也没有被缓存,而且看起来相当复杂。
我要补充一点,
Count
仍然必须遍历一些内部结构(如数组)来获取整个字典的锁,而Any()
将停在第一个非空桶上。我会说,对于一本大字典,Count
较慢,而对于一本小字典,它更快。
更正:
Count
在计数之前获取所有字典的锁定。它确实打电话 this.AcquireAllLocks()
。
请记住,这两种方法的结果都可能在方法返回之前被伪造,因为嘿......并发! :-)
我使用
属性还是 LINQ 的Count
有关系吗Any()
不。它们在功能上是相同的,并且性能差异应该很小。使用最恰当地传达含义的内容,并且仅在存在对整个应用程序的性能有重大影响的性能问题时才更改它。
Count
将在调用属性时计算字典中的项目。
Any
会调用ConcurrentDictionary.GenEnumerator()
来查看字典中是否有项目。根据 documentation,返回的枚举器将反映调用 GetEnumerator()
后对字典所做的更改。
因此,理论上,如果在调用
Any
和在 MoveNext
内调用 Any
之间添加一个项目,他们可能会得到不同的答案。然而,这个时间窗口应该很短,可能性应该很小。
还有谁能说哪个是正确的?如果您可以在添加项目时
Any
和Count
在完全相同的时间,那么集合是否为空?