Handling multiple inputs in the background in a C # .NET4 application

I am looking for a suitable model and the best modern way to solve the following problem:

My application expects input from several sources, for example: graphical interface, file system monitoring, voice command, web request, etc. When the input is received, I need to send it to some ProcessInput(InputData arg) method, which will start processing the data in the background without blocking the application to receive and process more data, and somehow return some results whenever processing is completed . Processing may take significantly less time, depending on the input. For starters, I do not need the ability to check progress or cancel processing.

After reading a dozen articles on MSDN and the blogs of some rock star programmers, I'm really confused about which template to use here, and more importantly, which .NET features

My findings:

Notes:

Performance is important, so if possible, using a multi-core system would be really enjoyable.

This is not a web application.

My problem reminds me of a TCP server (actually any server), where the application constantly listens for new connections / data on several sockets, I found the Asynchronous Socket Socket article, and I'm curious if this template might be a possible solution for me.

+4
source share
3 answers

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).

+3
source

An IMO using a thread pool is a way for the WRT to access input processing. Take a look at http://smartthreadpool.codeplex.com . It provides a very good API (using generics) to wait for results. You can use this in conjunction with the Asynchronous Socket Socket implementation. It might also be worth your while to take a look at Jeff Richter Power Threading Lib: http://www.wintellect.com/Resources/Downloads

+2
source

I am by no means an expert on these issues, but recently I did some research on this issue, and I am very pleased with the results achieved in the MS TPL library. Tasks give you a good wrapper around ThreadPool threads and are optimized for parallel processing, so they provide great performance. If you can use .NET 4.0 for your project, you should probably study the tasks. They represent a more advanced way of working with asynchronous operations and provide a good way to cancel operations using CancellationToken objects.

Here is a brief example of accessing a UI thread from another thread using tasks:

 private void TaskUse() { var task = new Task<string>(() => { Thread.Sleep(5000); return "5 seconds passed!"; }); task.ContinueWith((tResult) => { TestTextBox.Text = tResult.Result; }, TaskScheduler.FromCurrentSynchronizationContext()); task.Start(); } 

In the previous example, you can see how easy it is to synchronize with the user interface thread using TaskScheduler.FromCurrentSynchronizationContext (), assuming that you are calling this method from the user interface thread. Tasks also provide optimizations for blocking operations, such as scripts in which you need to wait for a service to respond, and by providing TaskCreationOptions.LongRunning for listing in the task designer. This ensures that this operation does not block the processor core, since the maximum number of active tasks is determined by the number of existing processor cores.

+1
source

Source: https://habr.com/ru/post/1387864/


All Articles