【问题标题】:await/async and going outside the box等待/异步并走出盒子
【发布时间】:2015-10-18 01:06:38
【问题描述】:

我有一个关于等待/异步的问题,以及在与预期略有不同的场景中使用异步方法,例如不直接等待它们。例如,假设我有两个需要并行完成的例程,它们都是异步方法(它们内部有等待)。我正在使用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放在method前面,就不再是Task了。是否有一些关于如何在普通等待之外处理异步方法的规则书?

【问题讨论】:

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


    【解决方案1】:

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

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

    应该可以正常工作。大致相当于这样:

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

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

    现在,如果您的方法实际上正在执行一些同步工作 - 例如,繁重的 CPU 绑定代码 - 那么您可能希望使用 Task.Run 来调用它们(如果您的调用代码在 UI 线程上)。

    【讨论】:

    • 啊,好吧,这实际上是有道理的。如果我有async Task<something>,那么我需要获取多个异步方法调用的结果怎么办?
    • @mmix:如果两个任务是同一类型(例如,Task<Something>),那么你可以做Something[] results = await Task.WhenAll(...);
    • 好吧,他们不是。我想这些人不能绕过代表。
    • @mmix:如果他们不是,那么你可以这样做var targetsTask = internalLoadAllEmailTargetsAsync(); var invoicesTask = internalEnumerateInvoicesAsync(); await Task.WhenAll(emailTask, invoicesTask); var targets = await targetsTask; var invoices = await invoicesTask;
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2022-01-02
      • 2016-05-09
      • 1970-01-01
      • 2011-04-25
      • 1970-01-01
      • 2023-03-12
      • 2016-07-07
      • 2016-03-25
      • 2017-10-09
      相关资源
      最近更新 更多