等待/异步并跳出框外

时间:2015-07-27 17:55:56

标签: c# .net multithreading asynchronous async-await

我有一个关于await / 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()
            }); 

这似乎对我来说过于复杂,因为我正在创建异步任务,其唯一目的是调用另一个任务。我不能只使用从异步方法状态引擎返回的任务吗?然而,我没有这样做,因为编译器将每个直接提到的异步方法都视为一个调用点:

{{1}}

如果它像这样,它似乎一个接一个地同步调用,如果我等待在方法前面,它就不再是一个任务。是否有关于如何在普通等待之外处理异步方法的规则书?

2 个答案:

答案 0 :(得分:7)

每个async方法都会同步开始执行,但是当它遇到第一个await时,它可能会异步运行。所以这一行:

await Task.WhenAll(internalLoadAllEmailTargetsAsync(), internalEnumerateInvoicesAsync());

应该工作得很好。它大致相当于:

var _1 = internalLoadAllEmailTargetsAsync();
var _2 = internalEnumerateInvoicesAsync();
await Task.WhenAll(_1, _2);

如果你的方法是真正的异步,那么这应该没问题。

现在,如果你的方法实际上正在进行一些同步工作 - 比如说,CPU密码量很大 - 那么你可能想要使用Task.Run来调用它们(如果你的调用代码在UI线程上)。 / p>

答案 1 :(得分:1)

你有一些代码,它会创建Task个对象,并且会像往常一样调用它,即同步调用。控件将仅在创建Task后返回到调用代码,如果async,它将在第一个await之后。 因此,如果它是一个问题,您的方法的某些部分将以阻塞方式调用,您可以在开头使用Task.Yield,只需要小心SynchronizationContext和线程切换。

但在大多数情况下,这种情况没有任何问题,因为创建Task的代码小而快,而实际的时序是由某种IO操作引起的。