请考虑以下代码:
public async Task<string> GetString()
{
//Some code here...
var data = await A();
//Some more code...
return data;
}
private async Task<string> A()
{
//Some code here..
var data = await B();
//manipulating data...
return data;
}
private async Task<string> B()
{
//Some code here..
var data = await C();
//manipulating data...
return data;
}
private async Task<string> C()
{
//Some code here..
var data = await FetchFromDB();
//manipulating data...
return data;
}
private async Task<string> FetchFromDB()
{
return await SOME_HTTP_REQUEST;
}
此代码演示了最基本的功能 - 嵌套异步方法。 每种方法都会转化为状态机吗?或者编译器是否足够复杂以生成更高效的结构? 在我的一些项目中,UI / WebAPI和I / O调用之间有大约20种方法 - 这是否会影响异步 - 等待开销(例如状态机)和非阻塞线程优势之间的权衡? 我的意思是,例如,如果4个状态机(4个嵌套的异步方法)的开销等于50ms的阻塞I / O(就权衡而言),则20状态机将等于更长的I / O延迟( 250毫秒)?
答案 0 :(得分:10)
await
无关紧要。 每个async
方法都会生成一个状态机(即使它根本没有await
个。)
您可以使用this TryRoslyn example查看。
如果您遇到不需要状态机的情况,那么该方法实际上不需要async
,例如:
private async Task<string> D()
{
var data = await FetchFromDB();
return data;
}
您可以删除async
关键字及其附带的状态机:
private Task<string> D()
{
return FetchFromDB();
}
但是否则,你实际上需要状态机,如果没有它,async
方法就无法运行。
您应该注意,与使用async-await
节省的资源相比,开销非常小,通常可以忽略不计。如果您意识到情况并非如此(通过测试),您可能只需要使该操作同步。
答案 1 :(得分:5)
每个方法都有一台状态机,是的。
请记住&#34;开销&#34;状态机主要是一个对象的分配(那个和几个goto
s,这将是非常快的),所以任何类型的&#34;优化&#34;你执行删除它与没有创建一次类的实例相同。
关于它的成本是否大于或小于同步工作,根据您的应用程序的具体情况,您需要执行性能基准测试。硬件肯定知道。
答案 2 :(得分:3)
每个方法都会转换为状态机吗?或者是 编译器是否足够复杂以生成更高效的结构?
不,编译器将为每个调用生成一个状态机。编译器不检查方法的语义调用链。它将仅基于方法生成状态机。
在查看已编译的代码时,您可以清楚地看到:
这是否会影响异步等待开销之间的权衡(例如 作为状态机)和非阻塞线程的好处?
您必须测试您的代码才能说出来。通常,当您需要吞吐量时,异步IO很好。如果您的异步方法将被多个呼叫者同时点击,您将能够看到其中的好处。如果没有,您可能看不到性能提升的任何影响。再次,对代码进行基准测试。