On Task.Factory.StartNew and Task.Run methods

Learn the best practices to create and schedule tasks efficiently in .Net using Task.Run and Task.Factory.StartNew methods

Task Parallel Library

Task Parallel Library

When creating tasks using Task.Factory.StartNew or Task.Run methods, you should keep certain important points in mind when writing asynchronous code. In most cases, it is advisable to avoid using Task.Factory.StartNew method if you are working with asynchronous code. If you are working with parallel code, I would say that StartNew is a good choice.

A task scheduler is a component that is responsible for scheduling tasks; The .Net framework provides you with two task schedulers. There's the default task scheduler that runs on the .Net framework thread pool, and there's the task scheduler that executes on the synchronization context of a specified target. The default task scheduler will suffice most of the time, but you can also build your own custom task scheduler to provide added functionalities. To build your own custom task scheduler you would need to create a class that extends the System.Threading.Tasks.TaskScheduler class.

How do I create Tasks using the Task Parallel Library?

There are several ways in which you can create and start tasks in .Net. You need to make use of the System.Threading.Tasks.Task or System.Threading.Tasks.Task<TResult> class to create tasks (a schedulable unit of work). While the former is used to create a task that doesn't return a value, the latter is used to create tasks that have return values. The Task.Factory property is an instance of the TaskFactory class. This property is used to create and schedule tasks. While the Task.Factory.StartNew method works like a fork operation and is used to create and start new tasks, the Wait method works just like a join operation and waits for the task to be complete.

The following code snippet illustrates how you can use the Task.Factory.StartNew method.

Task.Factory.StartNew(() => TestMethod(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

You can also create a Task using the Task.Run method as shown in the code snippet below.

public async Task DoSomeWork()

        {

            await Task.Run(() => TestMethod());

        }

        void TestMethod()

        {

            Console.WriteLine("Hello world!");

        }

If you would like to return a value from a Task you can take advantage of Task.FromResult method as shown in the code snippet below.

public async Task DoSomeWork()

   {

      string text = await Task.FromResult<string>(GetMessage());

   }

private string GetMessage()

   {

      return "Hello world!";

   }

You can also create tasks using a delegate or an action. The following code snippet shows how you can create tasks using actions and delegates.

Task task1 = new Task (new Action(Display));

task1.Start();

Task task2 = new Task (delegate { Display(); });

task2.Start();

You can also create tasks using lamba and anonymous methods.

Task.Factory.StartNew and Task.Run

Task.Factory.StartNew is a quick way of creating and starting a Task. Note that a call to Task.Factory.StartNew is functionally equivalent to creating a task instance and then calling the Start method on the instance. However, it is not recommended to be used for reasons aplenty. If you would like to execute synchronous code, Task.Factory.StartNew is not a good choice.

Note that if a task scheduler is available, the StartNew method will execute the task on that task scheduler. On the contrary, if a scheduler isn't available, it would execute the task on a thread pool thread. It should be noted that Task.Factory.StartNew defaults to TaskScheduler.Current and not TaskScheduler.Default.

Note that a call to Task.Run(action) is equivalent to the following statement: Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

On the contrary, a call to Task.Factory.StartNew(action) is equivalent to the following statement:
Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

If may want to use Task.Factory.StartNew if you have created a custom task scheduler and pass the scheduler instance to it explicitly. I would always recommend using Task.Run as it is much simpler and has safer defaults. In other words, we should avoid using Task.Factory.StartNew unless there is a need to create a task scheduler and then pass it explicitly when calling the StartNew method to create a new task and schedule it. If you were to use the TaskFactory.StartNew method effectively and reliably, you should use a custom task scheduler and then specify the CancellationToken and TaskCreationOptions.

The Task.Run method is recommended to use when you don't need to have much fine-grained control over thread scheduling and its intricacies. You should use Task.Run primarily on CPU bound methods. However, you should use Task.Run while invoking the task and not inside the implementation of the task. In other words, you should use Task.Run not inside any implementation of a method but at the point where the method is called. As an example, the following code snippet is an example of a "bad" piece of code.

public async Task<string> DownloadDataFromWebAsync(Uri uri)

        {

            return await Task.Run(() =>

            {

                using (WebClient webClient = new WebClient())

                {

                    return webClient.DownloadString(uri);

                }

            });

        }

Refer to the code snippet given above. The method isn't scalable as it would block the background thread, retrieve a thread from the thread pool and execute synchronously on it. Hence, it would consume more resources in your system.

This article is published as part of the IDG Contributor Network. Want to Join?

To comment on this article and other InfoWorld content, visit InfoWorld's LinkedIn page, Facebook page and Twitter stream.
From CIO: 8 Free Online Courses to Grow Your Tech Skills
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.