Home > Mobile >  Better solution for sync/async problem in desktop app?
Better solution for sync/async problem in desktop app?

Time:01-27

I have WinForms app where button click calls some async method of external library.

private async void button1_Click(object sender, EventArgs e)
{
    await CallLibraryAsync();
}

private static async Task CallLibraryAsync()
{
    var library = new Library();
    await library.DoSomethingAsync();
}

The library looks like this:

public class Library
{
    public async Task DoSomethingAsync()
    {
        Thread.Sleep(2000);
        await Task.Delay(1000).ConfigureAwait(false);

        // some other code
    }
}

Before any asynchronous code there is some calculation simulated by Thread.Sleep call. In that case this call will block UI thread for 2 seconds. I have no option to change the code in DoSomethingAsync.

If I want to solve blocking problem, I could call the library in Task.Run like this:

private static async Task CallLibraryAsync()
{
    var library = new Library();

    // added Task.Run
    await Task.Run(() => library.DoSomethingAsync());
}

It solves the problem, UI is not blocke anymore, but I've consumed one thread from ThreadPool. It is not good solution.

If I want to solve this problem without another thread, I can do something like this:

private static async Task CallLibraryAsync()
{
    var library = new Library();

    // added
    await YieldOnlyAsync().ConfigureAwait(false);

    await library.DoSomethingAsync();
}

// added
private static async Task YieldOnlyAsync()
{
    await Task.Yield();
}

This solution works. Task.Yield() causes that method YieldOnlyAsync() always runs asynchronously and ConfigureAwait(false) causes that next code (await library.DoSomethingAsync();) runs on some ThreadPool thread, not UI thread.

But it is quite complicated solution. Is there any simpler?

Edit:
If the library method looks like this

public class Library
{
    public async Task DoSomethingAsync()
    {
        await Task.Delay(1000).ConfigureAwait(false);
        Thread.Sleep(2000);
        await Task.Delay(1000);

        // some other code
    }
}

UI thread would not be blocked and I do not need to do anything. But that's the problem that it is some implementation detail I do not see directly because that could be in some nuget package. When I see that the UI freezes in some situations, I may find this problem (mean CPU-bound calculation before any await in async method) just after some investigation. There is no Wait() or Result, that would be easy to find, this is more problematic.

What I would like is to be prepared for that situation if possible in some simpler way. And that's why I do not want to use Task.Run whenewer I call some third-party library.

CodePudding user response:

If I want to solve blocking problem, I could call the library in Task.Run like this:

It solves the problem, UI is not blocke anymore, but I've consumed one thread from ThreadPool. It is not good solution.

This is exactly what you want to do in a WinForms app. CPU-intensive code should be moved to a separate thread to free up the UI thread. There isn't any downside to consuming a new thread in WinForms.

Use Task.Run to move it to a different thread, and wait asynchronously from the UI thread for it to complete.

To quote the enter image description here

It's definitely pretty sleepy:

enter image description here

So let's whack it into ILSpy with the Reflexil plugin loaded:

enter image description here

We can perhaps shorten that timeout a bit.. Right click, Edit..

enter image description here

Make it 1ms, Right click the assembly and Save As..

enter image description here

That's a bit quicker!

enter image description here

Have a play, NOP it out etc..

CodePudding user response:

When you use async/await for I/O or CPU-bound operations, your UI thread will not blocked. In your example, you use Thread.Sleep(2000);command for simulating your CPU-bound operations but this will block your thread-pool thread not UI thread. You can use Task.Delay(2000); for simulating your I/O operations without blocking thread-pool thread.

  •  Tags:  
  • Related