Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 707 Vote(s) - 3.47 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Async/await vs BackgroundWorker

#1
In the past few days I have tested the new features of .net 4.5 and c# 5.

I like its new async/await features. Earlier I had used [BackgroundWorker][1] to handle longer processes in the background with responsive UI.

My question is: after having these nice new features, when should I use async/await and when a [BackgroundWorker][2]? Which are the common scenarios for both?


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#2
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?
Reply

#3
This is a good introduction:

[To see links please register here]

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.

Reply

#4
[BackgroundWorker][1] 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"][2]
- Stephen Cleary's answer to [my question "Wasn't it .NET 4.0 TPL that made APM, EAP and BackgroundWorker asynchronous patterns obsolete?"][3]

MSDN article ["Asynchronous Programming with Async and Await (C# and Visual Basic)"][4] 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][5] **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][6] **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][7]'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][8] conditions.
The necessary part of it is multithreading and from the same MSDN article [Asynchronous Programming with Async and Await (C# and Visual Basic)][9]:

> 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][10]
- [Why does this code fail when executed via TPL/Tasks?][11]
- [await vs Task.Wait - Deadlock?][12]


[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

[8]:

[To see links please register here]

[9]:

[To see links please register here]

[10]:

[To see links please register here]

[11]:

[To see links please register here]

[12]:

[To see links please register here]

Reply

#5
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: [

[To see links please register here]

][1]

[1]:

[To see links please register here]

Reply

#6
Let's make an up-to-date comparison between a [`BackgroundWorker`][1] and the [`Task.Run`][2] + [`Progress<T>`][3] + [async/await][4] 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`][5] thread.

Advantages of the `BackgroundWorker` approach:

1. Can be used with projects targeting the [.NET Framework 4.0][6] 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`][7] 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][8]: the [`CancellationTokenSource`][9] + [`CancellationToken`][10] combo.
There are currently thousands of .NET APIs that consume a `CancellationToken`. On the contrary the `BackgroundWorker`s 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.

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

[8]:

[To see links please register here]

[9]:

[To see links please register here]

[10]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through