My application expects input of several sources, for example: graphical interface, file system monitoring, voice command, web request, etc.
At one time, I did a lot of asynchronous programming. It is useful for me to distinguish between background operations and asynchronous events. A "background operation" is what you initiate, and after a while it ends. An "asynchronous event" is something that always happens regardless of your program; You can subscribe, receive events on time, and then unsubscribe.
Thus, GUI inputs and file system monitoring would be examples of asynchronous events; whereas web requests are background operations. Background operations can also be divided into binding to the CPU (for example, processing some input in the pipeline) and binding to I / O (for example, a web request).
I make this distinction especially in .NET, because different approaches have different strengths and weaknesses. When making estimates, you must also consider how errors are propagated.
First, the parameters that you have already found:
ThreadPool.QueueUserWorkItem is almost the worst case. It can only process background operations (no events) and does not process I / O-bound operations. Return results and errors are both manual.BackgroundWorker (BGW) is not the worst, but certainly not the best. It also processes only background operations (no events) and does not process I / O-bound operations. Each BGW runs in its own thread - which is bad because you cannot take advantage of the self-employment of the thread pool. In addition, completion notifications (usually) are queued on a single thread, which can become a bottleneck on very busy systems.- An Event-Based Asynchronous Template (EAP) is the first option on your list that will support asynchronous events as well as background operations, and can also efficiently handle I / O-bound operations. However, it is somewhat difficult to program correctly and has the same problem as BGW, where completion notifications (usually) are all queued on one thread. (Note that BGW is an EAP applied to background operations bound to a processor). I wrote a library to help write EAP components along with some EAP-based sockets. But I do not recommend this approach; these days there are better options.
Tasks in a parallel task library - Task is the best option for background operations, both CPU-related and I / O binding. I am looking at several background work options on my blog - but this blog post does not affect asynchronous events at all.- C # 5
async / await - This allows a more natural expression of Task based background operations. They also offer an easy way to synchronize back to the caller context if you want (useful for UI initiated operations).
Of these options, async / await is the easiest to use, and Task is the second. The problem is that they were intended for background operations, not for asynchronous events.
Any source of an asynchronous event can be consumed using asynchronous operations (for example, Task ) if you have enough buffer for these events. When you have a buffer, you can simply restart the asynchronous operation every time it completes. Some buffers are provided by the OS (for example, sockets have readable buffers, user interface windows have message queues, etc.), but you may need to provide other buffers.
Having said that, here are my recommendations:
- Task-based Asynchronous Template (TAP) - Using
await / async or Task directly, use TAP to model at least your background operations. - TPL data stream (part of VS Async ) - allows you to configure pipelines for data transfer. The data stream is based on
Task s. The disadvantage of Dataflow is that it is still evolving and (IMO) is not as stable as the rest of Async support. - Reactive Extensions (Rx) is the only option specifically designed for asynchronous events, not just background operations. It is officially released (unlike VS Async and Dataflow), but the learning curve is steeper.
All three of these parameters are efficient (using a thread pool for any actual processing), and they all have well-defined semantics for handling errors and results. I recommend using TAP as much as possible; these parts can then be easily integrated into Dataflow or Rx.
You mentioned "voice commands" as one of the possible input sources. You may be interested in the BuildWindows video where Stephen Tub sings and uses Dataflow to harmonize his voice in near real time. (Stephen Tub - one of the geniuses for TPL, Dataflow and Async).