我们应该如何使用异步等待? [英] How should we use async await?
问题描述
我一直在研究如何使用异步等待,但是当我们有多个互相调用的方法时,我不太明白.我们应该始终使用等待还是仅在实际准备好使用结果时才使用等待?
例如,我们应该这样做吗?
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
和 Task.FromException<T>
像通常在async
方法中一样在返回的Task
上弹出任何异常.
无关紧要的例子
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
}
}
简而言之,如果您不太了解发生了什么,只需await
即可;开销将最小.但是,如果您了解如何返回任务结果,已完成任务,在任务上放置 exception 或只是转发.您可以保存一些 CIL 并通过删除async
关键字直接返回任务并绕过IAsyncStateMachine
来使代码获得较小的性能提升.
大约在这个时候,我将查找Stack&Overflow用户和作者 Stephen Cleary 和Parallel先生 Stephen Toub .他们有大量的博客和书籍专门讨论 Async and Await Pattern ,所有陷阱,编码礼节以及许多您肯定会感兴趣的信息.
I was looking at how to use async await, but I do not quite get it when we have multiple methods invoking each other. Should we always use await or should we only use await when we are actually ready to use the result?
So for example should we do it like this:
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();
}
Or like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
Task<string> Func1()
{
return Func2();
}
Task<string> Func2()
{
return tcpClient.ReadStringAsync();
}
Per example 1, should we always use await in every method?
Or
Per example 2 should we only use await on the top-most method when we start using the result?
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屋!