185

I just saw 3 routines regarding TPL usage which do the same job; here is the code:

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Create a task and supply a user delegate by using a lambda expression. 
    Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
    // Start the task.
    taskA.Start();

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                  Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Define and run the task.
    Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                      Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Better: Create and start the task in one operation. 
    Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                    Thread.CurrentThread.Name);

    taskA.Wait();                  
}

I just do not understand why MS gives 3 different ways to run jobs in TPL because they all work the same: Task.Start(), Task.Run() and Task.Factory.StartNew().

Tell me, are Task.Start(), Task.Run() and Task.Factory.StartNew() all used for the same purpose or do they have different significance?

When should one use Task.Start(), when should one use Task.Run() and when should one use Task.Factory.StartNew()?

Please help me to understand their real usage as per scenario in great detail with examples, thanks.

rory.ap
  • 34,009
  • 10
  • 83
  • 174
Mou
  • 15,673
  • 43
  • 156
  • 275
  • there is an [old article explaining that here](http://blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx) and [here for the newer `Task.Run`](http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx) - maybe this will answer your question ;) – Random Dev Apr 17 '15 at 07:53
  • [Here](http://stackoverflow.com/a/21427264/1768303) is an example of where `Task.Start` is actually useful. – noseratio Apr 17 '15 at 14:13
  • Possible duplicate of [What is the difference between Task.Run() and Task.Factory.StartNew()](https://stackoverflow.com/questions/38423472/what-is-the-difference-between-task-run-and-task-factory-startnew) – Michael Freidgeim Nov 01 '18 at 20:44

2 Answers2

217

Task.Run is a shorthand for Task.Factory.StartNew with specific safe arguments:

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

It was added in .Net 4.5 to help with the increasingly frequent usage of async and offloading work to the ThreadPool.

Task.Factory.StartNew (added with TPL in .Net 4.0) is much more robust. You should only use it if Task.Run isn't enough, for example when you want to use TaskCreationOptions.LongRunning (though it's unnecessary when the delegate is async. More on that on my blog: LongRunning Is Useless For Task.Run With async-await). More on Task.Factory.StartNew in Task.Run vs Task.Factory.StartNew

Don't ever create a Task and call Start() unless you find an extremely good reason to do so. It should only be used if you have some part that needs to create tasks but not schedule them and another part that schedules without creating. That's almost never an appropriate solution and could be dangerous. More in "Task.Factory.StartNew" vs "new Task(...).Start"

In conclusion, mostly use Task.Run, use Task.Factory.StartNew if you must and never use Start.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • 7
    u said "Don't ever create a Task and call Start()" redirect me to any good write up which will show that may causes by Task.Start(). i need details because u r saying to avoid it. thanks for reply. – Mou Apr 17 '15 at 08:06
  • r u talking about this link http://blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx ?? – Mou Apr 17 '15 at 08:09
  • @Mou indeed. specifically the big paragraph at the beginning. – i3arnon Apr 17 '15 at 08:11
  • 1
    @Mou `Task.Start` has its place for inheriting types mostly. – Yuval Itzchakov Apr 17 '15 at 08:40
  • it would be very nice if you pin point and discuss the problem of Task.Start() with example code. thanks – Mou Apr 17 '15 at 08:46
  • 1
    @Mou It's inefficient as it requires synchronization to make sure it's only called once. The other options do not. – i3arnon Apr 17 '15 at 08:48
  • @ i3arnon : i am not being able to visualize the issue u said " It's inefficient as it requires synchronization to make sure it's only called once" can u plzz discuss this issue with easy sample code to understand the root of the problem. thanks – Mou Apr 17 '15 at 08:54
  • 2
    @Mou You should probably read the post that explains this issue http://blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx – i3arnon Apr 17 '15 at 09:01
  • The synchronization cost should be negligible. Locks are expensive only when contested. – Theodor Zoulias Aug 20 '19 at 19:39
16

Short answer:

If you are not using nested children's tasks and always want your tasks to be executed on Thread Pool it is better to use Task.Run.

Long answer:

Task.Run and Task.Factory.StartNew both provides support for creating and scheduling Task objects so we don't need to create a Task and call Start()

Task.Run(action);

Is equivalent to:

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

And

Task.Factory.StartNew(action);

Is equivalent to:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

Task.Run uses TaskCreationOptions.DenyChildAttach which means that children's tasks can not be attached to the parent and it uses TaskScheduler.Default which means that the one that runs tasks on Thread Pool will always be used to run tasks.

Task.Factory.StartNew uses TaskScheduler.Current which means scheduler of the current thread, it might be TaskScheduler.Default but not always.

Ali Bayat
  • 3,561
  • 2
  • 42
  • 43