没有等待的 Dispatcher.BeginInvoke() 是否仍然异步执行?



我很难理解调度程序的异步方法和async/await之间的联系。

就我而言,我有一个在调度程序上执行操作的事件处理程序:

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

这应该不会阻止 UI 线程,对吧?至少在我们的应用程序中感觉像这样。与带有异步/等待的版本有什么区别?

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

这也很有效,似乎在 UI 响应能力方面没有区别。

这应该不会阻塞 UI 线程,对吧?

SomeLongRunningOperation()确实会在 UI 线程上运行并阻止。等待BeginInvoke方法的要点是,一旦SomeLongRunningOperation()在 UI 线程上完成执行,事件处理程序将恢复。因此,如果您在调用BeginInvoke后不执行任何操作,则在此处使用await关键字是没有意义的。

执行以下操作时,SomeLongRunningOperation方法完成之前将显示MessageBox

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

当您执行以下操作时,它将在完成后显示SomeLongRunningOperation

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

因此,如果在方法返回后不打算在事件处理程序中进行任何操作,则等待对BeginInvoke的调用是没有意义的。

请注意,这里的所有内容都在同一线程上运行。如果SomeLongRunningOperation是可能长时间运行的操作,则应在后台线程上执行它。最简单的方法是启动一个Task,您可以等待:

await Task.Run(SomeLongRunningOperation);

顾名思义BeginInvoke总是异步的。你要求Dispatcher(UI 线程(执行此操作,在你的情况下长时间运行,而不会阻止调用线程。如果决定改用Invoke,则调用线程将被阻止,直到Dispatcher完成执行您提供的委托。

BeginInvoke并不意味着工作在不同的线程上异步完成。您要做的是在另一个任务上启动此 SomeLongRunningOperation,并使用异步等待模式返回它,就像您在第二个示例中尝试的那样。像这样:

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

分配给Dispatcher的所有代码都在UI线程上运行。将TPL用于长时间运行的任务,Dispatcher仅用于更新 UI。

最新更新