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