我们应该如何使用异步等待? [英] How should we use async await?

查看:85
本文介绍了我们应该如何使用异步等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究如何使用异步等待,但是当我们有多个互相调用的方法时,我不太明白.我们应该始终使用等待还是仅在实际准备好使用结果时才使用等待?

例如,我们应该这样做吗?

async Task<string[]> FooAsync()
{
    var info = await Func1();
    return info.split('.');
}

async Task<string> Func1()
{
    return await Func2();
}

async Task<string> Func2()
{
    return await tcpClient.ReadStringAsync();
}

或者像这样:

async Task<string[]> FooAsync()
{
    var info = await Func1();
    return info.split('.');
}

Task<string> Func1()
{
    return Func2();
}

Task<string> Func2()
{
    return tcpClient.ReadStringAsync();
}

每个例子1,我们应该在每种方法中始终使用await吗?

根据示例2,当我们开始使用结果时,我们应该只在最上面的方法上使用await吗?

解决方案

每次调用await都会创建一大堆代码以捆绑变量,捕获同步上下文(如果适用),并在IAsyncStateMachine中创建一个延续.

从本质上讲,返回没有async 关键字Task将会为您带来较小的运行时效率,并为您节省大量的 CIL .请注意, .NET 中的 Async 功能也已经进行了许多优化.还要注意(并且重要的是)在using语句中返回Task可能会引发 Already Disposed Exception .

.

您可以在这里比较 CIL 和管道差异

因此,如果您的方法只是转发Task而不想要任何内容​​,则可以轻松地删除async关键字并直接返回Task.

更多-因此,有时候我们要做的不只是 forwarding ,而且还涉及分支.在这里 Task.FromResult 解决方案

Every-time you call await it creates a lump of code to bundle up variables, captures the synchronization context (if applicable) and create a continuation into an IAsyncStateMachine.

Essentially, returning a Task without the async keyword will give you a small run-time efficiency and save you a bunch of CIL. Do note that the Async feature in .NET also has many optimizations already. Also note (and importantly) that returning a Task in a using statement will likely throw an Already Disposed Exception.

You can compare the CIL and plumbing differences here

So if your method is just forwarding a Task and not wanting anything from it, you could easily just drop the async keyword and return the Task directly.

More-so, there are times when we do more than just forwarding and there is branching involved. This is where, Task.FromResult and Task.CompletedTask come into play to help deal with the logic of what may arise in a method. I.e If you want to give a result (there and then), or return a Task that is completed (respectively).

Lastly, the Async and Await Pattern has subtle differences when dealing with Exceptions. If you are returning a Task, you can use Task.FromException<T> to pop any exception on the the returned Task like an async method would normally do.

Nonsensical example

public Task<int> DoSomethingAsync(int someValue)
{
   try
   {
      if (someValue == 1)
         return Task.FromResult(3); // Return a completed task

      return MyAsyncMethod(); // Return a task
   }
   catch (Exception e)
   {
      return Task.FromException<int>(e); // Place exception on the task
   }
}

In short, if you don't quite understand what is going on, just await it; the overhead will be minimal. However, if you understand the subtitles of how to return a task result, a completed task, placing an exception on a task, or just forwarding. You can save your self some CIL and give your code a small performance gain by dropping the async keyword returning a task directly and bypassing the IAsyncStateMachine.


At about this time, I would look up the Stack Overflow user and author Stephen Cleary, and Mr. Parallel Stephen Toub. They have a plethora of blogs and books dedicated solely to the Async and Await Pattern, all the pitfalls, coding etiquette and lots more information you will surely find interesting.

这篇关于我们应该如何使用异步等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆