Async/Await VS Backgroundworker

Async/await vs BackgroundWorker

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?

C# backgroundworker RunworkerCompleted vs async await

Depend on what kind of work your MCIATS1Worker_DoWork method do, you can consider to use async-await approach, which makes code a little bid more cleaner.

private async Task MCIATS1WorkerDoWorkAsync()
{
await Task.Delay(1000) // do something asynchronously for 1 second
}

private async void MainWindow_Load(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
//some code
await MCIATS1WorkerDoWorkAsync();
MessageBox.Show("hello world");
}
}

Message box will be shown 10 times every 1 second. await keyword will continue loop only after MCIATS1WorkerDoWorkAsync method has successfully finished.

With async-await your form will remain responsive and if DoWork method do some IO operations, then you will not start another thread (as BackgroundWorker do) and whole execution will happens on one thread.

Updating background worker to async-await

I have a blog series that covers this in detail.

In short, BackgroundWorker is replaced by Task.Run, and ReportProgress (and friends) is replaced by IProgress<T>.

So, a straightforward translation would look like this:

async void SaveButtonClick(object sender, EventArgs e)
{
if (SaveFileDialog.ShowDialog() == DialogResult.OK)
{
ProgressWindow = new ProgressForm();
ProgressWindow.SetPercentageDone(0);
var progress = new Progress<int>(ProgressWindow.SetPercentageDone);
var task = SaveAndClose(SaveFileDialog.FileName, progress));
ProgressWindow.ShowDialog(this);
await task;
}
}

async Task SaveAndClose(string path, IProgress<int> progress)
{
await Task.Run(() => Save(path, progress));
ProgressWindow.Close();
}

void Save(string path, IProgress<int> progress)
{
// open file

for (int i=0; i < 100; i++)
{
// get some stuff from UI
// save stuff to file
if (progress != null)
progress.Report(i);
}

// close file
}

Notes for improvements:

  • It's not usually a good idea to have background threads reaching into the UI (// get some stuff from UI). It would probably work better if you could collect all the information from the UI before calling Task.Run and just pass it into the Save method.

Using await Task inside backgroundWorker is changing my status to complete

You can't use await inside a BackgroundWorker's DoWork. I recommend replacing BackgroundWoker completely with Task.Run:

Task task = null;

var timer = new Timer();
timer.Interval = 10000;
timer.Tick += Timer_Tick;
timer.Start();

private static async void Timer_Tick(object sender, EventArgs e)
{
if (task == null)
{
task = Task.Run(() => DoWorkAsync(frm));
try { await task; }
finally { task = null; }
}
}

private static async Task DoWorkAsync(Main frm)
{
using (var client = new HttpClient())
{
var result = await client.GetAsync(uri);
//message to user for answering, then return it to server again
}
}

Side note: I changed System.Timers.Timer to System.Windows.Forms.Timer so that the task variable is always accessed from the UI thread.

BackgroundWorker or Task, which to implement?

BackgroundWorker has been superseded by Tasks and in general you should use the latter when possible.

Note that besides Tasks having more features, there are also subtle differences which may be relevant. For instance, a Task may not necessarily be run on a different thread, while BackgroundWorker.DoWork does.

Arguably, BackgroundWorker is easier to use and you will still need it when developing in .NET versions prior to 4.

I wouldn't recommend refactoring your existing code, just start using Tasks in your new base. I also find Tasks easier to integrate with UIs but that may be subjective.



Related Topics



Leave a reply



Submit