Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async/await vs BackgroundWorker

People also ask

Is BackgroundWorker obsolete?

BackgroundWorker is explicitly labeled as obsolete in . NET 4.5: in the book By Joseph Albahari, Ben Albahari "C# 5.0 in a Nutshell: The Definitive Reference"

What is the difference between BackgroundWorker and thread?

A BackgroundWorker is a ready to use class in WinForms allowing you to execute tasks on background threads which avoids freezing the UI and in addition to this allows you to easily marshal the execution of the success callback on the main thread which gives you the possibility to update the user interface with the ...

Do work Async C#?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.

What is use of BackgroundWorker in C#?

BackgroundWorker is the class in System. ComponentModel which is used when you need to do some task on the back-end or in different thread while keeping the UI available to users (not freezing the user) and at the same time, reporting the progress of the same.


This is likely TL;DR for many, but, I think comparing await with BackgroundWorker is like comparing apples and oranges and my thoughts on this follow:

BackgroundWorker is meant to model a single task that you'd want to perform in the background, on a thread pool thread. async/await is a syntax for asynchronously awaiting on asynchronous operations. Those operations may or may not use a thread pool thread or even use any other thread. So, they're apples and oranges.

For example, you can do something like the following with await:

using (WebResponse response = await webReq.GetResponseAsync())
{
    using (Stream responseStream = response.GetResponseStream())
    {
        int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
    }
}

But, you'd likely never model that in a background worker, you'd likely do something like this in .NET 4.0 (prior to await):

webReq.BeginGetResponse(ar =>
{
    WebResponse response = webReq.EndGetResponse(ar);
    Stream responseStream = response.GetResponseStream();
    responseStream.BeginRead(buffer, 0, buffer.Length, ar2 =>
    {
        int bytesRead = responseStream.EndRead(ar2);
        responseStream.Dispose();
        ((IDisposable) response).Dispose();
    }, null);
}, null);

Notice the disjointness of the disposal compared between the two syntaxes and how you can't use using without async/await.

But, you wouldn't do something like that with BackgroundWorker. BackgroundWorker is usually for modeling a single long-running operation that you don't want to impact the UI responsiveness. For example:

worker.DoWork += (sender, e) =>
                    {
                    int i = 0;
                    // simulate lengthy operation
                    Stopwatch sw = Stopwatch.StartNew();
                    while (sw.Elapsed.TotalSeconds < 1)
                        ++i;
                    };
worker.RunWorkerCompleted += (sender, eventArgs) =>
                                {
                                    // TODO: do something on the UI thread, like
                                    // update status or display "result"
                                };
worker.RunWorkerAsync();

There's really nothing there you can use async/await with, BackgroundWorker is creating the thread for you.

Now, you could use TPL instead:

var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
                      {
                        int i = 0;
                        // simulate lengthy operation
                        Stopwatch sw = Stopwatch.StartNew();
                        while (sw.Elapsed.TotalSeconds < 1)
                            ++i;
                      }).ContinueWith(t=>
                                      {
                                        // TODO: do something on the UI thread, like
                                        // update status or display "result"
                                      }, synchronizationContext);

In which case the TaskScheduler is creating the thread for you (assuming the default TaskScheduler), and could use await as follows:

await Task.Factory.StartNew(() =>
                  {
                    int i = 0;
                    // simulate lengthy operation
                    Stopwatch sw = Stopwatch.StartNew();
                    while (sw.Elapsed.TotalSeconds < 1)
                        ++i;
                  });
// TODO: do something on the UI thread, like
// update status or display "result"

In my opinion, a major comparison is whether you're reporting progress or not. For example, you might have a BackgroundWorker like this:

BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (sender, eventArgs) =>
                            {
                            // TODO: something with progress, like update progress bar

                            };
worker.DoWork += (sender, e) =>
                 {
                    int i = 0;
                    // simulate lengthy operation
                    Stopwatch sw = Stopwatch.StartNew();
                    while (sw.Elapsed.TotalSeconds < 1)
                    {
                        if ((sw.Elapsed.TotalMilliseconds%100) == 0)
                            ((BackgroundWorker)sender).ReportProgress((int) (1000 / sw.ElapsedMilliseconds));
                        ++i;
                    }
                 };
worker.RunWorkerCompleted += (sender, eventArgs) =>
                                {
                                    // do something on the UI thread, like
                                    // update status or display "result"
                                };
worker.RunWorkerAsync();

But, you wouldn't deal with some of this because you'd drag-and-drop the background worker component on to the design surface of a form--something you can't do with async/await and Task... i.e. you won't manually create the object, set the properties and set the event handlers. you'd only fill in the body of the DoWork, RunWorkerCompleted, and ProgressChanged event handlers.

If you "converted" that to async/await, you'd do something like:

     IProgress<int> progress = new Progress<int>();

     progress.ProgressChanged += ( s, e ) =>
        {
           // TODO: do something with e.ProgressPercentage
           // like update progress bar
        };

     await Task.Factory.StartNew(() =>
                  {
                    int i = 0;
                    // simulate lengthy operation
                    Stopwatch sw = Stopwatch.StartNew();
                    while (sw.Elapsed.TotalSeconds < 1)
                    {
                        if ((sw.Elapsed.TotalMilliseconds%100) == 0)
                        {
                            progress.Report((int) (1000 / sw.ElapsedMilliseconds))
                        }
                        ++i;
                    }
                  });
// TODO: do something on the UI thread, like
// update status or display "result"

Without the ability to drag a component on to a Designer surface, it's really up to the reader to decide which is "better". But, that, to me, is the comparison between await and BackgroundWorker, not whether you can await built-in methods like Stream.ReadAsync. e.g. if you were using BackgroundWorker as intended, it could be hard to convert to use await.

Other thoughts: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html


async/await is designed to replace constructs such as the BackgroundWorker. While you certainly can use it if you want to, you should be able to use async/await, along with a few other TPL tools, to handle everything that's out there.

Since both work, it comes down to personal preference as to which you use when. What is quicker for you? What is easier for you to understand?


This is a good introduction: http://msdn.microsoft.com/en-us/library/hh191443.aspx The Threads section is just what you are looking for:

Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool.


BackgroundWorker is explicitly labeled as obsolete in .NET 4.5:

  • in the book By Joseph Albahari, Ben Albahari "C# 5.0 in a Nutshell: The Definitive Reference"
  • Stephen Cleary's answer to my question "Wasn't it .NET 4.0 TPL that made APM, EAP and BackgroundWorker asynchronous patterns obsolete?"

MSDN article "Asynchronous Programming with Async and Await (C# and Visual Basic)" tells:

The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool

UPDATE

  • in response to @eran-otzap's comment:
    "for IO-bound operations because the code is simpler and you don't have to guard against race conditions" What race conditions can occure , could you give an example ? "

This question should have been put as a separate post.

Wikipedia has a good explanation of racing conditions. The necessary part of it is multithreading and from the same MSDN article Asynchronous Programming with Async and Await (C# and Visual Basic):

Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool

That is, "The async and await keywords don't cause additional threads to be created".

As far as I can recall my own attempts when I was studying this article a year ago, if you have run and played with code sample from the same article, you could bump in situation that its non-async versions (you could try to convert it to yourself) block indefinitely!

Also, for concrete examples you could search this site. Here are some example:

  • Calling an async method with c#5.0
  • Why does this code fail when executed via TPL/Tasks?
  • await vs Task.Wait - Deadlock?

Let's make an up-to-date comparison between a BackgroundWorker and the Task.Run + Progress<T> + async/await combination. I will use both approaches to implement a simulated CPU-bound operation that must be offloaded to a background thread, in order to keep the UI responsive. The operation has a total duration of 5 seconds, and during the operation a ProgressBar must be updated every 500 msec. Finally the result of the calculation must be displayed in a Label. First the BackgroundWorker implementation:

private void Button_Click(object sender, EventArgs e)
{
    var worker = new BackgroundWorker();
    worker.WorkerReportsProgress = true;
    worker.DoWork += (object sender, DoWorkEventArgs e) =>
    {
        int sum = 0;
        for (int i = 0; i < 100; i += 10)
        {
            worker.ReportProgress(i);
            Thread.Sleep(500); // Simulate some time-consuming work
            sum += i;
        }
        worker.ReportProgress(100);
        e.Result = sum;
    };
    worker.ProgressChanged += (object sender, ProgressChangedEventArgs e) =>
    {
        ProgressBar1.Value = e.ProgressPercentage;
    };
    worker.RunWorkerCompleted += (object sender, RunWorkerCompletedEventArgs e) =>
    {
        int result = (int)e.Result;
        Label1.Text = $"Result: {result:#,0}";
    };
    worker.RunWorkerAsync();
}

24 lines of code inside the event handler. Now let's do exactly the same with the modern approach:

private async void Button_Click(object sender, EventArgs e)
{
    IProgress<int> progress = new Progress<int>(percent =>
    {
        ProgressBar1.Value = percent;
    });
    int result = await Task.Run(() =>
    {
        int sum = 0;
        for (int i = 0; i < 100; i += 10)
        {
            progress.Report(i);
            Thread.Sleep(500); // Simulate some time-consuming work
            sum += i;
        }
        progress.Report(100);
        return sum;
    });
    Label1.Text = $"Result: {result:#,0}";
}

17 lines of code inside the event handler. Quite less code overall.

In both cases the work is executed on a ThreadPool thread.

Advantages of the BackgroundWorker approach:

  1. Can be used with projects targeting the .NET Framework 4.0 and earlier.

Advantages of the Task.Run + Progress<T> + async/await approach:

  1. The result is strongly-typed. No need to cast from an object. No risk of a run-time InvalidCastException.
  2. The continuation after the completion of the work is running in the original scope, not inside a lamda.
  3. Allows to report arbitrary strongly-type information through the Progress. On the contrary a BackgroundWorker forces you to pass any extra information as an object, and then cast back from the object ProgressChangedEventArgs.UserState property.
  4. Allows to use multiple Progress objects, to report different progress data with different frequencies, easily. This is very tedious and error-prone with a BackgroundWorker.
  5. Canceling the operation follows the standard .NET pattern for cooperative cancellation: the CancellationTokenSource + CancellationToken combo. There are currently thousands of .NET APIs that consume a CancellationToken. On the contrary the BackgroundWorkers cancellation mechanism cannot be consumed because it doesn't generate notifications.
  6. Finally the Task.Run supports both synchronous and asynchronous workloads with the same ease. The BackgroundWorker can consume asynchronous APIs only by blocking the worker thread.