在多个线程上需要为Queue
设置Queue但在单个主线程上只需要Enqueue()
时,在C#中使用的最佳Dequeue()
数据结构是什么?我的线程结构如下所示:
- 主要主题 - 消费者
- Sub Thread1 - Producer
- Sub Thread2 - Producer
- Sub Thread3 - Producer
我有一个Queue<T> queue
,它包含子线程和主线程调用queue.Dequeue()
生成的所有项目,直到它为空。为此,我在主线程上调用了以下函数。
public void ConsumeItems()
{
while (queue.Count > 0)
{
var item = queue.Dequeue();
...
}
}
主线程通过每个线程循环调用此函数一次,我想确保我在线程安全的庄园中访问queue
但我还想避免在可能的情况下锁定queue
的原因。
答案 0 :(得分:1)
您要使用的是BlockingCollection<T>
,默认情况下由ConcurrentQueue<T>
支持。要从队列中获取项目,您可以使用foreach内的.GetConsumingEnumerable()
public BlockingCollection<Item> queue = new BlockingCollection<Item>();
public void LoadItems()
{
var(var item in SomeDataSource())
{
queue.Add(item);
}
queue.CompleteAdding();
}
public void ConsumeItems()
{
foreach(var item in queue.GetConsumingEnumerable())
{
...
}
}
当队列为空时,foreach将阻止该线程,并在项目可用时立即取消阻止。一旦.CompleteAdding()
被调用,foreach将完成处理队列中的任何项目,但一旦它为空,它将退出foreach块。
但是,在您执行此操作之前,我建议您查看TPL Dataflow,使用它,您不再需要管理队列或线程。它允许您构建逻辑链,并且链中的每个块都可以具有单独的并发级别。
public Task ProcessDataAsync(IEnumerable<SomeInput> input)
{
using(var outfile = new File.OpenWrite("outfile.txt"))
{
//Create a convert action that uses the number of processors on the machine to create parallel blocks for processing.
var convertBlock = new TransformBlock<SomeInput, string>(x => CpuIntensiveConversion(x), new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = Enviorment.ProcessorCount});
//Create a single threaded action that writes out to the textwriter.
var writeBlock = new ActionBlock<string>(x => outfile.WriteLine(x))
//Link the convert block to the write block.
convertBlock.LinkTo(writeBlock, new DataflowLinkOptions{PropagateCompletion = true});
//Add items to the convert block's queue.
foreach(var item in input)
{
await convertBlock.SendAsync();
}
//Tell the convert block we are done adding. This will tell the write block it is done processing once all items are processed.
convertBlock.Complete();
//Wait for the write to finish writing out to the file;
await writeBlock.Completion;
}
}