在。net 4.0中看到新的System.Collections.Concurrent命名空间,我非常激动,非常棒!我已经看到ConcurrentDictionary, ConcurrentQueue, ConcurrentStack, ConcurrentBag和BlockingCollection。
有一样东西似乎神秘地丢失了,那就是ConcurrentList<T>。我必须自己写吗(或者从网上得到:))?
我是不是遗漏了什么明显的东西?
在。net 4.0中看到新的System.Collections.Concurrent命名空间,我非常激动,非常棒!我已经看到ConcurrentDictionary, ConcurrentQueue, ConcurrentStack, ConcurrentBag和BlockingCollection。
有一样东西似乎神秘地丢失了,那就是ConcurrentList<T>。我必须自己写吗(或者从网上得到:))?
我是不是遗漏了什么明显的东西?
当前回答
你用ConcurrentList做什么?
在线程世界中,随机访问容器的概念并不像它看起来那样有用。该声明
if (i < MyConcurrentList.Count)
x = MyConcurrentList[i];
总的来说仍然不是线程安全的。
与其创建ConcurrentList,不如尝试使用现有的内容构建解决方案。最常见的类是ConcurrentBag,尤其是BlockingCollection。
其他回答
你用ConcurrentList做什么?
在线程世界中,随机访问容器的概念并不像它看起来那样有用。该声明
if (i < MyConcurrentList.Count)
x = MyConcurrentList[i];
总的来说仍然不是线程安全的。
与其创建ConcurrentList,不如尝试使用现有的内容构建解决方案。最常见的类是ConcurrentBag,尤其是BlockingCollection。
ConcurrentList(作为一个可调整大小的数组,而不是一个链表)不容易用非阻塞操作编写。它的API不能很好地转换为“并发”版本。
我很惊讶没有人提到使用LinkedList作为编写专业类的基础。
通常我们不需要各种集合类的完整API,如果您编写的主要是功能性副作用的免费代码,尽可能使用不可变的类,那么您实际上不会希望改变集合,以支持各种快照实现。
LinkedList solves some difficult problems of creating snapshot copies/clones of large collections. I also use it to create "threadsafe" enumerators to enumerate over the collection. I can cheat, because I know that I'm not changing the collection in any way other than appending, I can keep track of the list size, and only lock on changes to list size. Then my enumerator code simply enumerates from 0 to n for any thread that wants a "snapshot" of the append only collection, that will be guaranteed to represent a "snapshot" of the collection at any moment in time, regardless of what other threads are appending to the head of the collection.
我非常确定大多数需求通常非常简单,您只需要2或3个方法。编写一个真正的泛型库是非常困难的,但解决您自己的代码需求有时可以通过一两个技巧很容易。
LinkedList和优秀的函数式编程万岁。
干杯,……爱你们! 艾尔
附注:样本hack AppendOnly类在这里:https://github.com/goblinfactory/AppendOnly
System.Collections.Generic。List<t>对于多个读取器来说已经是线程安全的。试图使它对多个写入器是线程安全的是没有意义的。(原因Henk和Stephen已经提到了)
我试过一段时间(也:在GitHub)。我的实现出现了一些问题,我在这里就不赘述了。让我告诉你,更重要的是,我学到了什么。
首先,你不可能得到一个完整的IList<T>的无锁和线程安全的实现。特别是,随机插入和删除是行不通的,除非你也忘记了O(1)随机访问(也就是说,除非你“欺骗”,只是使用某种链表,让索引糟糕透顶)。
我认为可能值得的是一个线程安全的IList<T>的有限子集:特别是一个允许添加并通过索引提供随机只读访问的子集(但没有Insert、RemoveAt等,也没有随机写访问)。
This was the goal of my ConcurrentList<T> implementation. But when I tested its performance in multithreaded scenarios, I found that simply synchronizing adds to a List<T> was faster. Basically, adding to a List<T> is lightning fast already; the complexity of the computational steps involved is miniscule (increment an index and assign to an element in an array; that's really it). You would need a ton of concurrent writes to see any sort of lock contention on this; and even then, the average performance of each write would still beat out the more expensive albeit lockless implementation in ConcurrentList<T>.
在相对罕见的情况下,列表的内部数组需要调整自身的大小,您确实需要付出一点代价。因此,最终我得出结论,这是一个适合的场景,其中仅添加ConcurrentList<T>集合类型是有意义的:当您希望保证在每次调用中添加元素的开销较低时(因此,与平摊性能目标相反)。
它并不是一个像您想象的那样有用的类。