简体   繁体   中英

Is Dispatcher.BeginInvoke() without await still executed asynchronous?

I have a hard time understanding the connection between the asynchrnous methods of the dispatcher and async/await.

In my case I have an event handler that executes an operation on the dispatcher:

 private void OnEventOccurred(object sender, EventArgs e)
 {
     someControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeLongRunningOperation());
 }

This should not block the UI thread, right? At least it feels like it in our application. What is the difference to the version with async/await?

 private async void OnEventOccurred(object sender, EventArgs e)
 {
     await someControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeLongRunningOperation());
 }

This also works and doesn't seem to make a difference in terms of UI responsiveness.

BeginInvoke as the name suggests is always asynchronous. You're asking the Dispatcher (UI thread) to perform this operation, in your case long running, without blocking the calling thread. If you decided to use the Invoke instead, the calling thread gets blocked until the Dispatcher is done with executing the delegate you provided.

BeginInvoke does not imply that the work is done asynchronously on a different thread. What you would want to do is start this SomeLongRunningOperation on a different task and return it using the async await pattern as you tried in the second example. Something like this:

 private async void OnEventOccurred(object sender, EventArgs e)
 {
     await Task.Run(SomeLongRunningOperation());
 }

All the code assign to Dispatcher runs on UI thread. Use TPL for long running tasks and Dispatcher to update UI only.

This should not block the UI thread, right?

SomeLongRunningOperation() will indeed run on and block the UI thread. The point of awaiting the BeginInvoke method is that your event handler will resume once SomeLongRunningOperation() has finished executing on the UI thread. So if you don't do anything after the call the BeginInvoke , there is no point of using the await keyword here.

When you do the following, the MessageBox will be displayed before the SomeLongRunningOperation method has finished:

private void OnEventOccurred(object sender, EventArgs e)
{
    Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(SomeLongRunningOperation));
    MessageBox.Show("SomeLongRunningOperation will be executed eventually!");
}

And when you do the following, it will be display after SomeLongRunningOperation has finished:

private async void OnEventOccurred(object sender, EventArgs e)
{
    await Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(SomeLongRunningOperation));
    MessageBox.Show("SomeLongRunningOperation has been executed!");
}

So it's pointless to await the call to BeginInvoke if you don't intend to anything in your event handler after the method has returned.

Note that everything runs on the same thread here though. If SomeLongRunningOperation is a potentially long-running operation, you should execute it on a background thread. The easiest way to do this would be to start a Task , which you may await:

await Task.Run(SomeLongRunningOperation);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM