Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent winforms UI block when using async/await

I'm fairly new to async/await programming and sometimes I feel that I understand it, and then all of a sudden something happens and throws me for a loop.

I'm trying this out in a test winforms app and here is one version of a snippet that I have. Doing it this way will block the UI

private async void button1_Click(object sender, EventArgs e)
{

    int d = await DoStuffAsync(c);

    Console.WriteLine(d);

}

private async Task<int> DoStuffAsync(CancellationTokenSource c)
{

        int ret = 0;

        // I wanted to simulator a long running process this way
        // instead of doing Task.Delay

        for (int i = 0; i < 500000000; i++)
        {



            ret += i;
            if (i % 100000 == 0)
                Console.WriteLine(i); 

            if (c.IsCancellationRequested)
            {
                return ret;
            }
        }
        return ret;
}

Now, when I make a slight change by wrapping the body of "DoStuffAsync()" in a Task.Run it works perfectly fine

private async Task<int> DoStuffAsync(CancellationTokenSource c)
    {
        var t = await Task.Run<int>(() =>
        {
            int ret = 0;
            for (int i = 0; i < 500000000; i++)
            {



                ret += i;
                if (i % 100000 == 0)
                    Console.WriteLine(i);

                if (c.IsCancellationRequested)
                {
                    return ret;
                }
            }
            return ret;

        });


        return t;
    }

With all that said, what is the proper way to handle this scenario?

like image 842
Benji Avatar asked Nov 07 '15 21:11

Benji


People also ask

Does async await block UI thread?

Because await is only valid inside async functions and modules, which themselves are asynchronous and return promises, the await expression never blocks the main thread and only defers execution of code that actually depends on the result, i.e. anything after the await expression.

How can we avoid deadlock in async await?

NET) Avoid Context Switching to Improve Performance. In an application with user interface, the UI should only be updated on a UI thread (context). Other I/O or CPU bound works should be handled by worker threads from thread pool and not by the UI thread.

Can an async method run on the UI thread of a Windows Forms app?

You can start an async operation from the UI thread, await it without blocking the UI thread, and naturally resume on the UI thread when it's done. This is a very powerful feature, and most of the time you don't even need to think about it; it “just works”.

Does async await Block C#?

The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.


1 Answers

When you write such code:

private async Task<int> DoStuffAsync()
{
    return 0;
}

This way you are doing things synchronously, because you are not using await expression.

Pay attention to the warning:

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Based on the warning suggestion you can correct it this way:

private async Task<int> DoStuffAsync()
{
    return await Task.Run<int>(() =>
    {
        return 0;
    });
}

To learn more about async/await you can take a look at:

  • Async and Await by Stephen Cleary
  • Asynchronous Programming with Async and Await from msdn
like image 88
Reza Aghaei Avatar answered Sep 28 '22 08:09

Reza Aghaei