32

很简单:除了 ConcurrentDictionary (如果我必须使用它,但它不是真正正确的概念)之外,是否有任何 Concurrent 集合(IProducerConsumer 实现)支持基于项目或谓词的简单相等来删除特定项目定义移除条件?

说明:我有一个多线程、多阶段的工作流算法,它从数据库中提取对象并将它们放在“开始”队列中。从那里他们被下一阶段抓住,进一步处理,并塞进其他队列。这个过程会持续几个阶段。同时,第一阶段由其主管再次调用并将对象从数据库中拉出,这些对象可能包括仍在处理中的对象(因为它们尚未完成处理,因此尚未使用标志集重新持久化)他们完成了)。

我正在设计的解决方案是“工作中”的大师系列;对象在第一阶段检索以进行处理时进入该队列,并在工作流的任何阶段完成必要处理后将它们重新保存到数据库作为“已处理”后将其删除。当对象在该列表中时,如果它被第一阶段重新检索,它将被忽略。

我曾计划使用 ConcurrentBag,但唯一的删除方法 (TryTake) 从包中删除任意项目,而不是指定的项目(并且 ConcurrentBag在 .NET 4 中很慢)。ConcurrentQueue 和 ConcurrentStack 也不允许删除它会给你的下一个项目以外的项目,留下 ConcurrentDictionary,它可以工作但超出我的需要(我真正需要的是存储正在处理的记录的 Id;它们在工作流程中不会改变)。

4

3 回答 3

23

之所以没有这样的数据结构,是因为所有集合的查找操作时间为O(n). 这些是IndexOfRemove(element)等等。它们都枚举所有元素并检查它们是否相等。

只有哈希表的查找时间为 O(1)。在并发场景中,O(n) 查找时间会导致集合的锁定时间很长。在此期间,其他线程将无法添加元素。

在字典中,只有被哈希命中的单元格才会被锁定。当一个线程通过哈希单元中的元素检查相等性时,其他线程可以继续添加。

我的建议是继续使用 ConcurrentDictionary。


顺便说一句,您是对的,ConcurrentDictionary 对于您的解决方案来说有点过大。您真正需要的是快速检查对象是否在工作的天气。AHashSet将是一个完美的选择。那么它基本上什么都不做Add(element),,,Contains(element)Remove(element)java中有一个ConcurrentHeshSet实现。对于 c#,我发现了这个:How to implement ConcurrentHashSet in .Net don't know how good it is。

作为第一步,我仍然会编写一个带有HashSet接口的包装器,ConcurrentDictionary将其启动并运行,然后尝试不同的实现并查看性能差异。

于 2012-07-27T21:21:33.460 回答
6

正如其他帖子已经解释的那样,默认情况下不可能从Queue或删除项目ConcurrentQueue,但实际上最简单的解决方法是扩展或包装项目。

public class QueueItem
{
    public Boolean IsRemoved { get; private set; }
    public void Remove() { IsRemoved = true; }
}

出队时:

QueueItem item = _Queue.Dequeue(); // Or TryDequeue if you use a concurrent dictionary
if (!item.IsRemoved)
{
    // Do work here
}
于 2015-01-24T20:47:54.383 回答
1

在一般意义上使集合线程安全确实很难。线程安全有很多因素超出了库/框架类的责任或权限范围,这些因素会影响它真正“线程安全”的能力......正如你所指出的那样的缺点之一出来的是性能。编写一个也是线程安全的高性能集合是不可能的,因为它必须假设最坏的情况......

通常推荐的做法是使用您想要的任何集合并以线程安全的方式访问它。这基本上就是为什么框架中没有更多线程安全集合的原因。有关这方面的更多信息,请访问http://blogs.msdn.com/b/bclteam/archive/2005/03/15/396399.aspx#9534371

于 2012-07-27T21:20:34.913 回答