我发现自己对即将到来的.NET 4.0框架中存在 ConcurrentBag<T> 类很感兴趣:



我的问题是:如何实现这个想法?我熟悉的大多数集合本质上都是(在幕后)某种形式的数组,其中的顺序可能不“重要”,但是有一个顺序(这就是为什么,尽管不需要,但枚举会几乎总是经过一个不变的集合(按相同顺序是ListQueueStack等)。

如果我不得不猜测,我可能会建议在内部使用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可以包含重复项,并且不能通过索引进行访问,因此双向链接列表是实现的一个很好的选择。这样一来,锁定就可以非常精确地进行插入和删除(您不必锁定整个集合,而只需锁定要插入/删除的节点即可)。由于您不必担心重复,因此不涉及哈希。这样可以使双链表更加完美。

    10-08 08:31