SHARE:

Asynchronicity: Understanding the concepts of asynchronous tasks, parallel tasks and background tasks

Asynchronous programming is a set of techniques to implement expensive operations which are performed simultaneously with the rest of the program. Asynchronous programming is often used in the context of programs with a graphical user interface: it is generally unacceptable to freeze a user interface during the course of a time-consuming operation. In addition, asynchronous operations are important for server applications that need to manage multiple client requests simultaneously.

Background tasks

Sometimes when you execute an action, you do not need to wait for the result of this action, so you return the focus to the user for further events, for example, when you send an image to the server, the image resizing operation can be performed in the background. Here’s how to execute a task and to return the focus to the user : You just need to run a task with Task.Run() static method (available from .NET 4.5) If you work with .NET 4.0 Framework you need to use Task.Factory.StartNew() static method

using System;
using System.Threading.Tasks;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            Task.Run(() => { /* do something */});
        }
    }
}

You can read here the difference between there two methods : Task.Run vs Task.Factory.StartNew If you work with .NET 4.5.2 Framework you can do more : background tasks with .NET 4.5.2

Parallel tasks

Sometimes you have several  independents actions of each other to execute, thus when you run the second task after the previous one had been completed, we say they are executed synchronously, to gain speed of execution and return control to the user faster we can execute asynchronously between it, in other words we parallelize these tasks : here’s how: I will use Task.Run() static method (available from .NET 4.5), but as the latest paragraph if you are using .NET 4.0 Framework you can use Task.Factory.StartNew() static method

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            /*Build an array of tasks wich return a value*/
            Task[] tasks = new Task[3];

            /*Define each tasks to parallelize*/
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000); 
                                                return 1; });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); 
                                                return "True"; });

            /*Wait for all tasks execution are completed*/
            Task.WaitAll(tasks);

            /*Get an array of values returned by parallelized tasks array*/
            object[] results = tasks.Select(m => m.Result).ToArray();

            /*Get each values*/
            bool result0 = (bool)results[0];
            int result1 = (int)results[1];
            string result2 = (string)results[2];
        }
    }
}

1- I define an array of tasks

2- I add in the array each tasks i want to parallelize

3- I perform all tasks and I expect that all tasks are completed

4- I extract results form each task

5- I get each value with it type from the array of results

Under these conditions , total time of execution will take 5 sec VS 12 sec in synchronously conditions Same same reasoning without results back :
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            //Build an array of tasks wich return a value
            Task[] tasks = new Task[3];

            //Define each tasks to parallelize
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000); });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); });

            //Wait for all tasks execution are completed
            Task.WaitAll(tasks);
        }
    }
}

Asynchronous tasks

Asynchronicity is essential for activities that are potentially blocking, such as when your application accesses the web. Access to a web resource sometimes is slow or delayed. If such an activity is blocked within a synchronous process, the entire application must wait. In an asynchronous process, the application can continue with other work that doesn’t depend on the web resource until the potentially blocking task finishes. Examples how it works with a back result and not :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async Task DoSimpleWorkAsync()
        {
            bool value = await Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            return value;
        }

        public async Task DoSimpleWork2Async()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

Keywords async / await are required – The marked async method can use Await or await to designate suspension points. The await operator tells the compiler that the async method can’t continue past that point until the awaited asynchronous process is complete. In the meantime, control returns to the caller of the async method. – The suspension of an async method at an await expression doesn’t constitute an exit from the method, and finally blocks don’t run. – The marked async method can itself be awaited by methods that call it.

Mix asynchronous tasks and parallelization

It’s possible to parallelize asynchronous tasks, let’s reuse previous examples :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async void DoWork()
        {
            //Build an array of tasks wich return a value
            Task[] tasks = new Task[3];

            //Define each tasks to parallelize
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000);
                                                return 1; });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); 
                                                return "True"; });

            //Wait for all tasks execution are completed
            await Task.WhenAll(tasks);

            //Get an array of values returned by parallelized tasks array
            object[] results = tasks.Select(m => m.Result).ToArray();

            //Get each values
            bool result0 = (bool)results[0];
            int result1 = (int)results[1];
            string result2 = (string)results[2];
        }
    }
}

Note that it is very important not to use Task.WaitAll () but Task.WhenAll () when keywords async / await, Task.WaitAll () is intended to be used with synchronous tasks and Task is used . WhenAll () with asynchronous tasks! Synchronous and asynchronous tasks do not mix! ;)

Mix asynchronous tasks and background tasks

Sometimes it could be interesting to launch tasks in background, but these tasks could be asynchronous , in order to launch non blocking tasks in background, for example it could be usefull to use this way when several longs tasks (potentially blocking) are launched on the server when when server activity is already elevated
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async void DoWork()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

Another syntax works but i worse than the first shown previlously, if an exception occurs , with async void, exception will be “observed” unlike the following with async Task:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async Task DoWork()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

I hope this article has helped you understand the world of asynchronicity, the future of computing! 😉

Written by

anthonygiretti

Anthony is a specialist in Web technologies (14 years of experience), in particular Microsoft .NET and learns the Cloud Azure platform. He has received twice the Microsoft MVP award and he is also certified Microsoft MCSD and Azure Fundamentals.
%d bloggers like this: