I'm creating an indexer which is Enqueueing items which needs to be processed. The indexer will add items to its processor. It will for example add 100 items, then doesn't add items for 3 minutes and add another 50 items.
public class Processer
{
private ConcurrentQueue<Item> items;
public void AddItem(Item item)
{
this.items.Enqueue(item);
}
}
The items will come in at random intervals, so I will create a separate thread to dequeue and process these items.
What would be the best option to use?
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
Changelog
- Changed to BlockingCollection
- Changed back to ConcurrentQueue
Some things I've checked:
- De-queue Items with worker threads (using ThreadPool)
- Thread queues for dummies (only using Thread solutions, not the TPL)
- Unexpected behaviour for ThreadPool.QueueUserWorkItem (same as above)
- C# - ThreadPool vs Tasks stating TPL is preferred when using multi threaded code