什么时候多个等待是有意义的

本文关键字:有意义 等待 什么时候 | 更新日期: 2023-09-27 18:22:47

我对c#async/await机制有一些误解。之间有什么本质区别吗

private async void Init()
{
    await Task.Run(() => Do1());
    await Task.Run(() => Do2());
}

private async void Init()
{
    await Task.Run(() => 
    {
       Do1();
       Do2();
    });
}

我看到的唯一区别是:在第一个示例中,Do1和Do2将在不同的线程中运行,而在第二个示例中——在同一个线程中。但是,它的真正好处是什么?什么时候我应该更喜欢第一种方法而不是第二种方法,反之亦然?


编辑:第二种情况

有什么区别

private async void Init()
{
    await Task.Run(() => Do1());
    Do3();
}

private async void Init()
{
    await Task.Run(() => 
    {
       Do1();
       Do3();
    });
}

什么时候多个等待是有意义的

区别在于:

第一个例子:

  • 在线程池线程上对Do1进行排队并异步等待它完成,然后对Do2执行完全相同的操作。这些可能在不同的线程上运行
  • Do1Do2排队,以便在同一线程池线程上一个接一个地同步执行

第二个例子:

  • 在线程池上对Do1进行排队并异步等待其完成,然后同步调用Do3
  • 这与第一个示例的第二部分完全相同

请注意,当您await时,您异步地等待操作完成,因此,除非该方法完成,否则它不会执行下一行代码。

我假设你在问自己,一个是否比另一个更可取,在大多数情况下,这取决于情况。如果您在控制台应用程序中运行,并且无论如何都要异步等待Do1完成,那么将两个方法传递给同一个Task.Run调用。如果您计划在同步很重要的地方(例如GUI应用程序)执行此操作,那么任何需要与UI控件交互的操作都应该在UI线程上调用。

另一种更常见的选择是,当您有两个彼此独立的操作,并且您想一起启动它们并等待两者完成时。这就是您使用Task.WhenAll:的地方

var firstDo = Task.Run(() => Do1());
var secondDo = Task.Run(() => Do2());
await Task.WhenAll(firstDo, secondDo);

旁注:

不要在没有返回值的异步方法中使用async void,这就是async Task的作用。前者只是为了允许与事件处理程序兼容,我假设情况并非如此。

  • 如果Do1()Do2()彼此独立,则应该分别运行它们。如果它们是长时间运行/阻塞的进程,则这一点更为重要
  • 另一方面,如果它们是相关的,并且第一个线程执行另一个线程所需的一些操作,那么最好在一个线程中运行它们,以减少线程开销。毕竟,你事先就知道它们需要按顺序运行