我发现自己对即将到来的.NET 4.0框架中存在 ConcurrentBag<T>
类很感兴趣:
我的问题是:如何实现这个想法?我熟悉的大多数集合本质上都是(在幕后)某种形式的数组,其中的顺序可能不“重要”,但是有一个顺序(这就是为什么,尽管不需要,但枚举会几乎总是经过一个不变的集合(按相同顺序是List
,Queue
,Stack
等)。
如果我不得不猜测,我可能会建议在内部使用Dictionary<T, LinkedList<T>>
;但是考虑到只使用T
类型的键是没有道理的,实际上这似乎是很可疑的。
我期望/希望的是,这实际上是一个已建立的对象类型,已经在某个地方“弄清楚了”,并且知道该已建立类型的人可以告诉我。这对我来说是非常不寻常的-在现实生活中易于理解但很难转化为开发人员的可用类的概念之一-这就是为什么我对可能性感到好奇的原因。
编辑:
一些响应者建议Bag
在内部可以是哈希表的一种形式。这也是我最初的想法,但是我预见了这个想法的两个问题:
正如Meta-Knight建议的那样,也许有一个例子可以使这一点更加清楚:
public class ExpensiveObject() {
private ExpensiveObject() {
// very intense operations happening in here
}
public ExpensiveObject CreateExpensiveObject() {
return new ExpensiveObject();
}
}
static void Main() {
var expensiveObjects = new ConcurrentBag<ExpensiveObject>();
for (int i = 0; i < 5; i++) {
expensiveObjects.Add(ExpensiveObject.CreateExpensiveObject());
}
// after this point in the code, I want to believe I have 5 new
// expensive objects in my collection
while (expensiveObjects.Count > 0) {
ExpensiveObject expObj = null;
bool objectTaken = expensiveObjects.TryTake(out expObj);
if (objectTaken) {
// here I THINK I am queueing a particular operation to be
// executed on 5 separate threads for 5 separate objects,
// but if ConcurrentBag is a hashtable then I've just received
// the object 5 times and so I am working on the same object
// from 5 threads at the same time!
ThreadPool.QueueUserWorkItem(DoWorkOnExpensiveObject, expObj);
} else {
break;
}
}
}
static void DoWorkOnExpensiveObject(object obj) {
ExpensiveObject expObj = obj as ExpensiveObject;
if (expObj != null) {
// some work to be done
}
}
最佳答案
如果查看ConcurrentBag<T>
的详细信息,您会发现它基本上是一个自定义的链接列表。
由于Bags可以包含重复项,并且不能通过索引进行访问,因此双向链接列表是实现的一个很好的选择。这样一来,锁定就可以非常精确地进行插入和删除(您不必锁定整个集合,而只需锁定要插入/删除的节点即可)。由于您不必担心重复,因此不涉及哈希。这样可以使双链表更加完美。