c# - 立即等待异步任务与先声明然后等待

标签 c# asynchronous async-await task

让我们看下面的两个例子:

public class MyClass 
{
    public async Task Main() 
    {
        var result1 = "";
        var result2 = "";

        var request1 = await DelayMe();
        var request2 = await DelayMe();

        result1 = request1;
        result2 = request2;        
    }

    private static async Task<String> DelayMe()
    {
        await Task.Delay(2000);
        return "";
    }
}

和:

public class MyClass 
{
    public async Task Main() 
    {
        var result1 = "";
        var result2 = "";

        var request1 = DelayMe();
        var request2 = DelayMe();

        result1 = await request1;
        result2 = await request2;        
    }

    private static async Task<String> DelayMe()
    {
        await Task.Delay(2000);
        return "";
    }
}

第一个示例展示了您通常如何编写 async await 代码,其中一件事发生在另一件事之后并正确等待。

第二个是先调用 async Task 方法,但稍后会await

第一个示例执行时间超过 4000ms,因为 await 在发出第二个请求之前计算第一个请求;但是第二个示例花费了 2000ms 多一点。发生这种情况是因为 Task 实际上在执行越过 var request1 = DelayMe(); 行时就开始运行,这意味着 request1request2 并行运行。在这一点上,await 关键字似乎只是确保计算了 Task

第二种方法的感觉和行为类似于 await Task.WhenAll(request1, request2),但在这种情况下,如果 2 个请求中出现问题,您将立即获得异常而不是等待计算所有内容,然后获取 AggregateException

我的问题是,使用第二种方法并行运行多个 awaitable Task 时是否存在缺点(性能或其他方面)依赖于对方的处决?查看降低的代码,看起来第二个示例为每个等待的项目生成了等量的 System.Threading.Tasks.Task1,而第一个示例则没有。这是否仍在通过 async await` 状态机流程?

最佳答案

if something fails in the 2 requests, you will get an exception instantly instead of waiting for everything to compute and then getting an AggregateException.

如果第一个 请求失败,那么是。如果在第二个 请求中出现问题,那么不,您不会检查第二个请求结果,直到该任务被awaited。

My question is that is there a drawback (performance or otherwise) in using the second approach to run multiple awaitable Tasks in parallel when the result of one doesn't depend on the execution of the other? Looking at the lowered code, it looks like the second example generates an equal amount of System.Threading.Tasks.Task1per awaited item while the first one doesn't. Is this still going through theasync await` state-machine flow?

它仍在通过状态机流程。我倾向于推荐 await Task.WhenAll,因为代码的意图更明确,但有些人不喜欢“即使有异常也总是等待”的行为。另一方面,Task.WhenAll 总是收集所有异常 - 如果您有快速失败行为,那么可以忽略一些异常。

关于性能,并发执行会更好,因为可以并发执行多个操作。没有线程池耗尽的危险,因为 async/await 不使用额外的线程。

作为旁注,我建议为此使用术语“异步并发”而不是“并行”,因为对许多人来说“并行”意味着并行处理,即 Parallel 或 PLINQ,它在这种情况下使用的技术是错误的。

关于c# - 立即等待异步任务与先声明然后等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57310058/

相关文章:

c# - 调用 GetSubkeyNames() 后无法访问注册表?

javascript - 如何使用 JS promises 捕获异步错误?

javascript async/await unhandledRejection 未触发

async-await - 安全性,Thread.CurrentPrincipal和ConfigureAwait(false)

c# - Entity Framework : am I supposed to modify migration classes?

c# - Windows 服务加 GUI/C#

c# nhibernate id 是否在删除时自动重置?

actionscript-3 - 我应该如何在访问器中执行异步操作?

c# - 谁有我可以看到的异步网络请求的简单实现?

c# - CPU 计算与 IO 操作的异步等待用法?