Why does Task.Factory.StartNew return immediately when Task.Run is not working?

Consider this piece of code:

Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Run(async () => { await Task.Delay(4000); }); } for (var i = 0; i < tasks.Length; ++i) await tasks[i]; Console.WriteLine("Done!"); 

This works as expected to complete 4,000 ms. However, if I exchange Task.Run with Task.Factory.StartNew , it only takes 0.006 ms!

Can someone explain why?

+5
source share
3 answers

Ok, I found the answer myself after reading this https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/

Using the async keyword here, the compiler is about to display that delegate will be Func<Task<int>> : the delegate call will be returned to Task<int> to represent the possible completion of this call. And also since the delegate is Func<Task<int>> , TResult is equal to Task<int> , and therefore the type 't will be Task<Task<int>> , not Task<int> .

So, this code works as expected:

 Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Factory.StartNew(async () => { await Task.Delay(4000); }); } for (var i = 0; i < tasks.Length; ++i) await await (tasks[i] as Task<Task>); Console.WriteLine("Done!"); 

What can be implemented with Unwrap :

 Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Factory.StartNew(async () => { await Task.Delay(4000); }).Unwrap(); } for (var i = 0; i < tasks.Length; ++i) await tasks[i]; Console.WriteLine("Done!"); 
+3
source

Can someone explain why?

Simply put, StartNew does not understand async delegates.

So, when your delegate returns an incomplete task on his first await , StartNew sees the delegate exit and considers that his work is completed, that’s why he returns Task<Task> here. Task.Run has special logic for handling asynchronous delegates, automatically deploying an internal task.

This is just one of the problems of using StartNew with asynchronous code; I will talk more about this and others in my StartNew Dangerous blog StartNew .

+5
source

Answer here

there is a difference in behavior between the two methods: Task.Run (Action) by default does not allow you to perform child tasks with the TaskCreationOptions.AttachedToParent parameter to attach to the current instance of the task, whereas StartNew (Action) does

So, Task.Run will wait for the completion of the execution, and Task.Factory.StartNew will immediately return the task.

+3
source

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


All Articles