我有一个应用程序,其ConcurrentQueue项目具有ID属性和每个项目的ConcurrentQueue任务,队列项目如下所示:
class QueueItem {
public int ID { get; set; }
public ConcurrentQueue<WorkItem> workItemQueue { get; set; }
}
并且队列本身看起来像:
ConcurrentQueue<QueueItem> itemQueue;
我有一个线程在itemQueue上做一个foreach,从每个队列中取出一个项目并对其进行处理:
foreach(var queueItem in itemQueue) {
WorkItem workItem;
if (queueItem.workItemQueue.TryDequeue(out workItem))
doWork(workItem);
else
// no more workItems for this queueItem
}
我正在使用ConcurrentQueues,因为我有一个单独的线程可能将queueItems添加到itemQueue,并将workItems添加到每个workItemQueue。
当我在queueItem中没有更多workItem时,我的问题就出现了 - 我想从itemQueue中删除那个queueItem - 就像......
if (queueItem.workItemQueue.TryDequeue(out workItem))
doWork(workItem);
else
itemQueue.TryRemove(queueItem);
......但我找不到办法轻松做到这一点。我想出的方法是将每个QueueItem出列,然后如果workItemQueue中仍有WorkItems,则将其排队:
for (int i = 0; i < itemQueue.Count; i++) {
QueueItem item;
itemQueue.TryDequeue(out queueItem);
if (queueItem.workItemQueue.TryDequeue(out workItem)) {
itemQueue.Enqueue(queueItem);
doWork(workItem);
}
else
break;
}
有没有更好的方法来实现我想要的PFX ConcurrentQueue,或者这是一种合理的方法,我应该使用自定义并发队列/列表实现还是我错过了什么?
答案 0 :(得分:4)
通常,没有有效的方法可以从队列中删除特定项目。它们通常具有O(1)队列并且已经出列,但O(n)将被删除,这是您的实现所做的。
一种替代结构叫做LinkedHashMap。如果您有兴趣,请查看Java implementation。
它本质上是一个哈希表和一个链表,允许O(1)队列,出队和删除。
这还没有在.Net中实现,但是网上有一些实现。
现在,问题是,为什么itemQueue是一个队列?从您的代码示例中,您永远不会从中排队或出列任何内容(除了导航删除问题)。我怀疑如果使用更合适的数据结构可以简化您的问题。您能举例说明其他代码访问itemQueue吗?
答案 1 :(得分:3)
这可能不适合所有人,但以下是我提出的从并发队列中删除项目的解决方案,因为这是第一个谷歌结果,我想我会留下我的解决方案。
我所做的是暂时将工作队列替换为空,将原始文件转换为列表并删除项目,然后从修改后的列表中创建一个新队列并将其放回。
在代码中(抱歉这是VB.net而不是C#):
Dim found As Boolean = False
//'Steal the queue for a second, wrap the rest in a try-finally block to make sure we give it back
Dim theCommandQueue = Interlocked.Exchange(_commandQueue, New ConcurrentQueue(Of Command))
Try
Dim cmdList = theCommandQueue.ToList()
For Each item In cmdList
If item Is whateverYouAreLookingFor Then
cmdList.Remove(item)
found = True
End If
Next
//'If we found the item(s) we were looking for, create a new queue from the modified list.
If found Then
theCommandQueue = New ConcurrentQueue(Of Command)(cmdList)
End If
Finally
//'always put the queue back where we found it
Interlocked.Exchange(_commandQueue, theCommandQueue)
End Try
旁白:这是我的第一个答案,所以请随意提出一些编辑建议和/或编辑我的答案。
答案 2 :(得分:0)
队列是指您希望处理FIFO样式的项目,即LIFO的堆栈。还有一个concurrentdictionary和concurrentbag。确保队列实际上是您想要的。我不认为我会在同时发生的事情上做过预告。
您可能需要的是工作项的单个队列(让它们使用公共接口并在接口上创建队列,接口应该公开继承的类型,如果需要,可以在以后重新创建它)。如果工作项属于父项,则可以使用一个属性,该属性将保存父项的键(考虑键的GUID),并且父项可以保存在并发字典中,并根据需要引用/删除。
如果您必须按照自己的方式进行,请考虑添加标记。然后,您可以将项目队列中的项目标记为“已关闭”或其他任何内容,以便在它出列时将被忽略。