.net, C# tip, Performance

Using the BackgroundWorker object in C# to improve application responsiveness

Most of the software that I build is for the web – because of that, I’ve not had to deal with using threads too much. In fact, there was only one time that I have worked on a web project where threads were used – a (seriously smart) developer built something using threads that was a pre-cursor to the .NET Async/Await model. It worked great when it worked, but it wasn’t our favourite bit of the codebase to make changes to.

puppy_multithreading

Recently I’ve been doing some Windows Forms development, and I’ve come up against the old problem of the GUI freezing when I performed an processor intensive operation. I wanted to find a way of carrying out this intensive operation on a different thread to the GUI, but ideally I wanted a way to avoid the traditional code complexity when trying to manage and release different threads.

The BackgroundWorker object

A colleague recommended that I look into the BackgroundWorker object – this object allows an intensive operation to work on a different thread to the GUI, and I can interact with this through an event model.

I’ll try to cut this down to the absolute bare bones before looking at an example. There are two events that I really care about – DoWork and RunWorkerCompleted.

  • I put the intensive operation into the DoWork event handler.
  • If anything needs to be done when the intensive operation completes (e.g. a notification), this goes into RunWorkerCompleted.

Finally, I can start the BackgroundWorker thread by calling the RunWorkerAsync() method.

How to use a BackgroundWorker

The code below isn’t meant to represent best practice – it’s a bare bones explanation of how to use the BackgroundWorker’s most important events.

I used Visual Studio to create a sample Windows Form application – inside the form’s code behind class, the form’s constructor is extremely simple:

public SampleForm() {
    InitializeComponent();  
}

Now I can add the code for the background worker – I’ve pasted the code for the class below.

public partial class SampleForm : Form
{
    private BackgroundWorker worker = new BackgroundWorker();

    public SampleForm()
    {
        InitializeComponent();

        // register background worker events
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;

        // start background worker in different thread to the GUI
        worker.RunWorkerAsync();
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // This is where the processor intensive code should go
        ProcessorIntensiveCode();

        // if we need any output to be used, put it in the DoWorkEventArgs object
        e.Result = "all done";
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // will output "all done" to the console
        Console.WriteLine((string)e.Result);
    }
}

And that’s about it – no need for complex thread management code. There’s quite a bit more that can be done with this object – you can report on progress for example, and report back to the GUI thread how far you’ve got through the intensive operation. But hopefully this explains the core features of this really useful class.