"await"关键字能否导致并行代码?

3
假设我有两个异步函数:
Result1 result1 = await getResult1();
Result2 result2 = await getResult2();
doSomething(result1, result2);

理想情况下,我希望编译器分析我的方法并看到getResult2()不依赖于getResult1()的结果,并将其编译为同时运行两者的代码,等待两者的结果后再继续。

问题1:这是发生了什么吗?

问题2:如果不是,假设Result1Result2没有共同的基类型,我该如何做才能实现这一点,因此无法使用Task.WhenAll()


1
在.NET中,“不共享基类型”非常不寻常。你是否返回指针类型? - Ben Voigt
@BenVoigt 我的意思是除了 object 以外...我当然可以装箱和拆箱,但那似乎不是惯用的方法。 - George Mauer
async-await 关注的是异步性而非并行性。 - Paulo Morgado
2个回答

7

是这样发生的吗?

不是。 await 意味着更多或更少地说,“在以下任务完成之前,请勿继续执行代码”。

我该怎么做才能实现这一点

首先启动两个任务,然后等待它们都完成:

var firstTask = getResult1();
var secondTask = getResult2();
await Task.WhenAll(firstTask, secondTask);
doSomething(firstTask.Result, secondTask.Result);

由于返回类型不同,所以WhenAll在这里无法工作,对吗? - George Mauer
1
@GeorgeMauer 为什么不行呢?调用 await 的结果并不是非常有用;但我们也不需要它,因为我们有任务本身。如果我们没有存储任务,并尝试从调用 WhenAll 的结果中获取结果,那么我们就需要处理它。 - Servy
只是为了完整起见 - 没有语言功能可以自动做到我想要的吗? - George Mauer
1
@GeorgeMauer 你的意思是说,拿出必须按照特定顺序运行的项目,并且无序执行它们吗?不,那是不可能的。如果你想一开始就不指定它们必须按照特定顺序完成,那很容易,我已经向你展示了其中的一种方法。但是,如果你想改变这种行为,你需要实际上更改代码。 - Servy
1
没有await就是一个被美化的.ContinueWith(,它重用旧的SynchronizationContext,并将发生在await之后的所有代码作为函数参数传递。所以你基本上做了getResult1().ContinueWith(() => getResult2(). ContinueWith(() => doSomething(result1, result2))); 你明确地说:“做这个,等待结果,然后做这个,等待结果,然后做最后一个函数”,所以编译器不能优化它,因为它会删除你明确的指令,不要并行执行它们。 - Scott Chamberlain
显示剩余7条评论

4
  1. No, in your code you are waiting for the first result before starting the second operation.

  2. First start both tasks, then await them:

    Task<Result1> task1 = getResult1();
    Task<Result2> task2 = getResult2();
    doSomething(await task1, await task2);
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接