【发布时间】:2010-12-13 22:00:45
【问题描述】:
我发现自己对即将到来的 .NET 4.0 框架中存在 ConcurrentBag<T> 类非常感兴趣:
当订购无关紧要时,包对于存储对象很有用,而且与集合不同,包支持重复。
我的问题是:如何实现这个想法?我熟悉的大多数集合基本上相当于(在引擎盖下)某种形式的数组,其中的顺序可能并不“重要”,但有一个顺序(这就是为什么,即使它没有不需要,枚举几乎总是会经过一个未更改的集合,无论是List、Queue、Stack 等,都以相同的顺序)。
如果我不得不猜测,我可能会建议在内部它可能是Dictionary<T, LinkedList<T>>;但考虑到仅使用 any 类型 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
}
}
【问题讨论】:
-
+1 因为很高兴知道这个类的存在
-
Dan-o:您在示例代码中的 5 行注释毫无意义。当然,此时你的包里有 5 个独立的对象。[public ExpensiveObject CreateExpensiveObject()] 中的“new”运算符保证了这一点。
-
@Boogaloo:看看 Meta-Knight 和 flyfishr64 的回复。他们建议
Bag可以实现为 HashTable,其中对象作为键,值设置为关联键的出现次数。 如果是这种情况,那么“添加”一个对象与将该值(出现次数)加一相同,“删除”一个对象将返回该对象并简单地减少该值价值。你是对的,CreateExpensiveObject 会保证一个对象是创建的,但不能保证它被添加到Bag,如果实现是一个哈希表。 -
嗯..我的错误。我过去没有使用过哈希。我假设默认的哈希生成器会为每个对象创建一个唯一的哈希值——你可以用自己的哈希生成器覆盖它。别管我。 :)
标签: .net language-agnostic collections bag