Recently I read an article on Habré ( upd: from the comments I realized that I need to attach a quote, on which further the question)
As soon as the code reaches the Task.Run () method, another thread gets from the thread pool and the code that we passed to Task.Run () is executed in it. The old stream, as it should be for a decent stream, returns to the pool and waits for him to be called to do the work again. The new thread executes the transferred code, reaches the synchronous operation, synchronously executes it (waits until the operation is completed) and proceeds along the code. In other words, the operation remained synchronous: we, as before, use the stream during the execution of a synchronous operation. The only difference is that we spent the time on context switching when calling Task.Run () and returning to ExecuteOperation (). Things got a little worse.
One of the issues that is considered there: the Task.Run call is the Task.Run - Task.Run , and is needed only for the responsiveness of the GUI.
The question is about Task.Run(() => _anyWork()) , where _anyWork() contains a synchronous code. What is written in the article sounds logical enough, if you do this:
await DoWork(); ... Task DoWork() => Task.Run(_work); Yes, in this case, an extra load is created on the thread pool. But, if you do this:
var task1 = DoWork1(); var task2 = DoWork2(); var task3 = DoWork3(); await Task.WhenAll(task1, task2, task3); Task.Run immediately turns into a normal code, right?
The thread that will execute this code will create three other threads ( upd : made a reservation: initiates the addition of work to the queue that will be launched in the ThreadPool ), which will simultaneously perform their work in parallel. Further, when he meets await , he will return control (as a result, he will most likely return to the pool). Please correct if not so.
If this is so, then the question arises: where does this line lie, between a bad implementation and a normal one? In a non-library code, it is clear that if a method is called and waiting somewhere further, then you can do Task.Run . In the library, on the one hand, we can parallelize the work of our methods if the client waits for them after the call. On the other - we can in vain increase the load if the client will expect the result immediately upon a call. To know exactly how the client will call methods - we cannot, we can only give recommendations in the documentation.
Perhaps there are some official MS recommendations? On msdn, I found only a dry description of how the methods work.
Task.Rundoes not create a new thread, but takes a ready stream from the pool - tym32167Task.Run сразу превращается в нормальный код, ведь так?What does a normal code mean? Critical code normality? - tym32167создается лишняя нагрузка на пул потоковpool of threads exists in order to load it. What does overload mean? - tym32167Task.Runand you draw some conclusions about the applicability ofTask.Runonly by this example? Let's and C # ban m thread pool, they, too, in the example, have the same role asTask.Run- tym32167Task.Runis your choice. If the current flow doesn’t bother you, do it in sync - tym32167