我很难理解调度程序的异步方法和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。