Await /async和跳出框框
本文关键字:async Await | 更新日期: 2023-09-27 18:05:03
我有一个关于await/async和在与预期略有不同的场景中使用async方法的问题,例如不直接等待它们。例如,假设我有两个例程需要并行完成,其中两个例程都是异步方法(它们内部有等待)。我正在使用await TAsk.WhenAll(...)
,它反过来期望等待某种任务列表。我所做的是这样的:
await Task.WhenAll(new Task[]
{
Task.Run(async () => await internalLoadAllEmailTargets()),
Task.Run(async () => await internalEnumerateInvoices())
});
这对我来说似乎过于复杂,因为我正在创建异步任务,其唯一目的是调用另一个任务。我不能只是使用从异步方法状态引擎返回的任务吗?然而,我没有做到这一点,因为编译器将每个直接提到的异步方法都视为调用点:
// this doesn't seem to work ok
await Task.WhenAll(new Task[]
{
internalLoadAllEmailTargets(),
internalEnumerateInvoices()
});
如果是这样,它似乎一个接一个地同步调用,如果我在方法前面放置await,它就不再是Task了。在普通等待之外,是否有一些关于如何处理异步方法的规则手册?
每个async
方法开始同步执行,但是当它到达第一个await
时,它可能会异步执行。所以这一行:
await Task.WhenAll(internalLoadAllEmailTargetsAsync(), internalEnumerateInvoicesAsync());
应该可以正常工作。它大致相当于:
var _1 = internalLoadAllEmailTargetsAsync();
var _2 = internalEnumerateInvoicesAsync();
await Task.WhenAll(_1, _2);
如果你的方法是真正异步的,那么这应该没问题。
现在,如果你的方法实际上在做一些同步工作——比如说,繁重的cpu绑定代码——那么你可能想用Task.Run
来调用它们(如果你的调用代码在一个UI线程上)。
您有一些代码,创建Task
对象,它将像往常一样被调用,即同步。控件只有在创建Task
之后才会返回给调用代码,而在创建async
的情况下,它将在第一个await
之后返回。因此,如果您的方法的某些部分将以阻塞方式调用,这是一个问题,您可以在开始时使用Task.Yield
,只是要小心SynchronizationContext
和线程切换。
但是在大多数情况下,这种情况并没有什么问题,因为创建Task
的代码既小又快,而实际的计时是由某种IO操作引起的。