仍未异步执行的Dispatcher.BeginInvoke()是否仍异步执行?

时间:2018-09-27 07:07:36

标签: c# wpf async-await dispatcher

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

对于我来说,我有一个事件处理程序,该事件处理程序在调度程序上执行操作:

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

这不应阻止UI线程,对吗?至少在我们的应用程序中感觉像。与使用async / await的版本有什么区别?

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

这也有效,并且在UI响应性方面似乎没有什么改变。

3 个答案:

答案 0 :(得分:1)

顾名思义,

BeginInvoke始终是异步的。您要让Dispatcher(UI线程)在长时间运行的情况下执行此操作,而不会阻塞调用线程。如果您决定改用Invoke,则在执行您提供的委托完成Dispatcher之前,调用线程将被阻塞。

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

  

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

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

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

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);