当我们在linq查询中使用并发集合时,它们是线程安全的吗?并发集合和不可变集合之间的区别是什么??
所有linq方法都通过IEnumerable工作,因此它们使用GetEnumerator方法的实现。从ConcurrentDictionary的源代码中,我可以看到微软对GetEnumerator实现的评论:
从字典返回的枚举器可以安全地与同时使用读取和写入字典,但它并不代表即时快照字典的。通过枚举器公开的内容可能包含修改在被调用后被编入词典。
这意味着您可以枚举ConcurrentDictionary,但它可能会在枚举过程中被其他线程修改,因此您可以通过枚举获得部分更新的字典。为了防止这种情况,您可以通过在枚举前调用dict.ToArray或使用dict.Keys或dict.Values来获取字典的快照-它们在内部获取快照。
ConcurrentStack、ConcurrentQueue和ConcurrentBag的工作方式不同:
枚举表示内容的即时快照堆栈的。它不反映之后对集合的任何更新被调用。枚举器可以安全使用同时对堆栈进行读取和写入。
这意味着当您开始迭代时,您将获得当前堆栈/队列的快照,因此其他线程无法更改它。
至于并发集合和不可变集合之间的区别,Ariex的回答给了您一个很好的解释。
据我所知,不可变集合意味着你只能读取它的值,而不能更改它们,这在并发场景中很好,因为只有所有的读取。并发集合类似于不可变集合,但它为您提供了更多的功能来允许您编辑它。不可变集合自然是线程安全的,并发集合是线程安全