What is the difference between Task.Run() and Task.Factory.StartNew()
The second method, Task.Run
, has been introduced in a later version of the .NET framework (in .NET 4.5).
However, the first method, Task.Factory.StartNew
, gives you the opportunity to define a lot of useful things about the thread you want to create, while Task.Run
doesn't provide this.
For instance, lets say that you want to create a long running task thread. If a thread of the thread pool is going to be used for this task, then this could be considered an abuse of the thread pool.
One thing you could do in order to avoid this would be to run the task in a separate thread. A newly created thread that would be dedicated to this task and would be destroyed once your task would have been completed. You cannot achieve this with the Task.Run
, while you can do so with the Task.Factory.StartNew
, like below:
Task.Factory.StartNew(..., TaskCreationOptions.LongRunning);
As it is stated here:
So, in the .NET Framework 4.5 Developer Preview, we’ve introduced thenew Task.Run method. This in no way obsoletes Task.Factory.StartNew,but rather should simply be thought of as a quick way to useTask.Factory.StartNew without needing to specify a bunch ofparameters. It’s a shortcut. In fact, Task.Run is actuallyimplemented in terms of the same logic used for Task.Factory.StartNew,just passing in some default parameters. When you pass an Action toTask.Run:
Task.Run(someAction);
that’s exactly equivalent to:
Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
People already mentioned that
Task.Run(A);
Is equivalent to
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
But no one mentioned that
Task.Factory.StartNew(A);
Is equivalent to:
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);
As you can see two parameters are different for Task.Run
and Task.Factory.StartNew
:
TaskCreationOptions
-Task.Run
usesTaskCreationOptions.DenyChildAttach
which means that children tasks can not be attached to the parent, consider this:var parentTask = Task.Run(() =>{ var childTask = new Task(() => { Thread.Sleep(10000); Console.WriteLine("Child task finished."); }, TaskCreationOptions.AttachedToParent); childTask.Start(); Console.WriteLine("Parent task finished.");});parentTask.Wait();Console.WriteLine("Main thread finished.");
When we invoke
parentTask.Wait()
,childTask
will not be awaited, even though we specifiedTaskCreationOptions.AttachedToParent
for it, this is becauseTaskCreationOptions.DenyChildAttach
forbids children to attach to it. If you run the same code withTask.Factory.StartNew
instead ofTask.Run
,parentTask.Wait()
will wait forchildTask
becauseTask.Factory.StartNew
usesTaskCreationOptions.None
TaskScheduler
-Task.Run
usesTaskScheduler.Default
which means that the default task scheduler (the one that runs tasks on Thread Pool) will always be used to run tasks.Task.Factory.StartNew
on the other hand usesTaskScheduler.Current
which means scheduler of the current thread, it might beTaskScheduler.Default
but not always. In fact when developingWinforms
orWPF
applications it is required to update UI from the current thread, to do this people useTaskScheduler.FromCurrentSynchronizationContext()
task scheduler, if you unintentionally create another long running task inside task that usedTaskScheduler.FromCurrentSynchronizationContext()
scheduler the UI will be frozen. A more detailed explanation of this can be found here
So generally if you are not using nested children task and always want your tasks to be executed on Thread Pool it is better to use Task.Run
, unless you have some more complex scenarios.
See this blog article that describes the difference. Basically doing:
Task.Run(A)
Is the same as doing:
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);