What is the difference between Task.Run() and Task.Factory.StartNew()

C#MultithreadingTask Parallel-Library

C# Problem Overview


I have Method :

private static void Method()
{
    Console.WriteLine("Method() started");

    for (var i = 0; i < 20; i++)
    {
        Console.WriteLine("Method() Counter = " + i);
        Thread.Sleep(500);
    }

    Console.WriteLine("Method() finished");
}

And I want to start this method in a new Task. I can start new task like this

var task = Task.Factory.StartNew(new Action(Method));

or this

var task = Task.Run(new Action(Method));

But is there any difference between Task.Run() and Task.Factory.StartNew(). Both of them are using ThreadPool and start Method() immediately after creating instance of the Task. When we should use first variant and when second?

C# Solutions


Solution 1 - C#

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 the > new Task.Run method. This in no way obsoletes Task.Factory.StartNew, > but rather should simply be thought of as a quick way to use > Task.Factory.StartNew without needing to specify a bunch of > parameters. It’s a shortcut. In fact, Task.Run is actually > implemented in terms of the same logic used for Task.Factory.StartNew, > just passing in some default parameters. When you pass an Action to > Task.Run:

Task.Run(someAction);

> that’s exactly equivalent to:

Task.Factory.StartNew(someAction, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Solution 2 - C#

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:

  1. TaskCreationOptions - Task.Run uses TaskCreationOptions.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 specified TaskCreationOptions.AttachedToParent for it, this is because TaskCreationOptions.DenyChildAttach forbids children to attach to it. If you run the same code with Task.Factory.StartNew instead of Task.Run, parentTask.Wait() will wait for childTask because Task.Factory.StartNew uses TaskCreationOptions.None

  1. TaskScheduler - Task.Run uses TaskScheduler.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 uses TaskScheduler.Current which means scheduler of the current thread, it might be TaskScheduler.Default but not always. In fact when developing Winforms or WPF applications it is required to update UI from the current thread, to do this people use TaskScheduler.FromCurrentSynchronizationContext() task scheduler, if you unintentionally create another long running task inside task that used TaskScheduler.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.

Solution 3 - C#

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

Solution 4 - C#

The Task.Run got introduced in newer .NET framework version and it is recommended.

> Starting with the .NET Framework 4.5, the Task.Run method is the > recommended way to launch a compute-bound task. Use the StartNew > method only when you require fine-grained control for a long-running, > compute-bound task.

The Task.Factory.StartNew has more options, the Task.Run is a shorthand:

> The Run method provides a set of overloads that make it easy to start > a task by using default values. It is a lightweight alternative to the > StartNew overloads.

And by shorthand I mean a technical shortcut:

public static Task Run(Action action)
{
    return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
        TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
}

Solution 5 - C#

According to this post by Stephen Cleary, Task.Factory.StartNew() is dangerous:

> I see a lot of code on blogs and in SO questions that use Task.Factory.StartNew to spin up work on a background thread. Stephen Toub has an excellent blog article that explains why Task.Run is better than Task.Factory.StartNew, but I think a lot of people just haven’t read it (or don’t understand it). So, I’ve taken the same arguments, added some more forceful language, and we’ll see how this goes. :) StartNew does offer many more options than Task.Run, but it is quite dangerous, as we’ll see. You should prefer Task.Run over Task.Factory.StartNew in async code.

Here are the actual reasons:

> 1. Does not understand async delegates. This is actually the same as > point 1 in the reasons why you would want to use StartNew. The problem > is that when you pass an async delegate to StartNew, it’s natural to > assume that the returned task represents that delegate. However, since > StartNew does not understand async delegates, what that task actually > represents is just the beginning of that delegate. This is one of the > first pitfalls that coders encounter when using StartNew in async > code. > 2. Confusing default scheduler. OK, trick question time: in the > code below, what thread does the method “A” run on?

Task.Factory.StartNew(A);

private static void A() { }

> Well, you know it’s a trick question, eh? If you answered “a thread > pool thread”, I’m sorry, but that’s not correct. “A” will run on > whatever TaskScheduler is currently executing!

So that means it could potentially run on the UI thread if an operation completes and it marshals back to the UI thread due to a continuation as Stephen Cleary explains more fully in his post.

In my case, I was trying to run tasks in the background when loading a datagrid for a view while also displaying a busy animation. The busy animation didn't display when using Task.Factory.StartNew() but the animation displayed properly when I switched to Task.Run().

For details, please see https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html

Solution 6 - C#

Apart from the similarities i.e. Task.Run() being a shorthand for Task.Factory.StartNew(), there is a minute difference between their behaviour in case of sync and async delegates.

Suppose there are following two methods:

public async Task<int> GetIntAsync()
{
    return Task.FromResult(1);
}

public int GetInt()
{
    return 1;
}

Now consider the following code.

var sync1 = Task.Run(() => GetInt());
var sync2 = Task.Factory.StartNew(() => GetInt());

Here both sync1 and sync2 are of type Task<int>

However, difference comes in case of async methods.

var async1 = Task.Run(() => GetIntAsync());
var async2 = Task.Factory.StartNew(() => GetIntAsync());

In this scenario, async1 is of type Task<int>, however async2 is of type Task<Task<int>>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSergiy LichenkoView Question on Stackoverflow
Solution 1 - C#ChristosView Answer on Stackoverflow
Solution 2 - C#Mykhailo SeniutovychView Answer on Stackoverflow
Solution 3 - C#Scott ChamberlainView Answer on Stackoverflow
Solution 4 - C#Zein MakkiView Answer on Stackoverflow
Solution 5 - C#user8128167View Answer on Stackoverflow
Solution 6 - C#Shubham SharmaView Answer on Stackoverflow