我正在创建一个索引器,它会将需要处理的项目加入队列。索引器将把项目添加到其处理器中。例如,它会添加100个项目,然后3分钟内不再添加项目,接着再添加50个项目。
public class Processer
{
private ConcurrentQueue<Item> items;
public void AddItem(Item item)
{
this.items.Enqueue(item);
}
}
这些项目将以随机间隔出现,因此我将创建一个单独的线程来出队并处理这些项目。
使用哪个选项最好?
Don't use a Collection, but use the ThreadPool:
public void AddItem(Item item) { ThreadPool.QueueUserWorkItem(function, item); }
This will automatically create a Queue, and process the items, but I have less control, when 20 items are found, they will almost stop my indexer to run and first finish this thread pool
Use a long running Task:
public Processer() { this.task = Task.Factory.StartNew(() => DequeueItems(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } public DequeueItems() { while(true) { Item item = null; while(this.items.TryDequeue(out item) { this.store.ExecuteIndex((AbstractIndexCreationTask)item); } Thread.Sleep(100); } }
But I hate the while() and thread.sleep I've got to use, since the enumerable will dry up after some time, and it will need recheck if there are new items.
Use a short running task:
public Processer() { } private void Run() { this.task = Task.Factory.StartNew(() => DequeueItems(), CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); } public void AddItem(Item item) { this.items.Add(item); if(this.task == null || this.task.isCompleted) this.Run(); } public DequeueItems() { Item item = null; while(this.items.TryDequeue(out item) { this.store.ExecuteIndex((AbstractIndexCreationTask)item); } }
This might be nicer? But starting a thread is a "expensive" operation, and I don't know if I can miss items since I check IsCompleted, which can be in the process of ending the while loop and this way missing 1 item. But it doesn't sleep, and use a dirty while loop.
Your option, since MSDN recommends to use the TPL, I thought not to use Threads, but maybe there are better ways dealing with this problem
更新日志
- 更改为BlockingCollection
- 又改回了ConcurrentQueue
我检查过的一些事情:
- 使用线程池(ThreadPool)实现工作线程中的出队操作
- 线程队列入门 (只使用线程解决方案,不是TPL)
- ThreadPool.QueueUserWorkItem的意外行为 (同上)
- C# - ThreadPool vs Tasks 指出在使用多线程代码时,TPL是首选
BlockingCollection<T>
或ConcurrentQueue<T>
?BlockingCollection<T>
则是专门为像你这样的生产者/消费者情况而设计的。 - Jon SkeetGetConsumingEnumerable
会一直等待,直到调用CompleteAdding
,所以我仍然不理解Thread.Sleep
和while
循环的作用。 - Daniel Kelley