Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
160 views
in Technique[技术] by (71.8m points)

c# - Explain async await again

This is my event handler code:

protected async void TestrunSaveExecute()
{
    bool saveResult = await SaveTestRunAsync();
}

In order to keep the UI responsive, I used the async/await method.

In my understanding, I can now do some lengthy operations in SaveTestRunAsync() without blocking the UI, since it is decoupled by using the await keyword.

private async Task<bool> SaveTestRunAsync()
{
    //System.Threading.Thread.Sleep(5000); --> this blocks the UI
    await Task.Delay(5000); // this doesn't block UI

    return true;

}

Could you please explain why the call to Thread.Sleep still blocks the UI, and Task.Delay doesn't?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The code is still running on the UI thread.

It is not running on a background thread.

As such, any lengthy, costly, operation you're doing in that async method will still block the UI for that period of time.

Thread.Sleep puts the UI thread to sleep.

You need to understand how async and await works in this case.

await here basically says this:

Let's split the method in two here. The first portion is whatever executes up to the point of the await. The second portion is whatever should execute after the awaitable object has completed.

So, basically, the method executes up until it reaches await Task.Delay(5000);. Then it puts a "delay of 5 seconds" into play, and says "schedule the rest of the code to execute when that is done". Then it returns so that the UI thread can keep pumping messages.

Once the 5 seconds is up, the UI thread executes the rest of that method.

Basically, this is good if you do asynchronous I/O, but not so good if you do costly operations, like processing large datasets or similar.

So how then can you do that?

You can use Task.Run.

This will spin up another thread to execute the delegate it is given, and the UI thread is free to do other stuff in the meantime.

Basically you can think of a method using await as this:

Life of method:    <------------------------------------------------------->
Parts:             [ start of method ----][awaitable][ rest of method -----]

So the method will execute the first portion, until it reaches await X, then it will check if X is already done, if it's not done, it will set up some Task objects in such a way that the awaitable object gets to run, and once it has completed, the "rest of the method" gets to run.

If X was already done, perhaps it's an asynchronous I/O operation that has already completed, or it completed really fast, then the method will keep executing the rest of the method as though you hadn't written await there.

But if not, then it returns. This is important, because it lets the UI thread (in this case) get back to pumping messages like mouse clicks and things from the user.

Once the task waiting for that "awaitable object" is told that the awaitable is completed, the "rest of the method" is scheduled, which basically (in this case) puts a message into the message queue asking it to execute the rest of that method.

The more await statements you have in such a method, the more pieces, basically it will just split the method up into more parts.

You can do all of this with the Task class that was introduced in an earlier .NET version. The whole purpose of async / await is to make it easier to write code, since wrapping up your code in task objects had the unfortunate effect of turning your code inside out, and making it hard to handle things like exceptions and loops.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...