在异步方法中省略 async 和 await
在异步方法中省略 async 和 await
一个快速的问题;阅读这篇文章:http://blog.stephencleary.com/2016/12/eliding-async-await.html\n文章主要告诉我要使用async/await。我已经在使用了。然而,他还说当你在代理任务时不需要使用async部分。\n
// 简单的透传到下一层:省略。 TaskPassthroughAsync(int x) => _service.DoSomethingPrettyAsync(x); // 方法的简单重载:省略。 async Task DoSomethingPrettyAsync(CancellationToken cancellationToken) { ... // 核心实现,使用await。 }
\n为什么在透传时不使用async/await呢?这难道不是更方便吗?这有意义吗?\n任何人有想法吗?
为什么在传递时不应使用async/await?
因为只要你键入await,编译器就会添加大量的实现代码,而这些代码对你来说完全无用——调用者已经可以直接等待代理任务。
如果我添加类似于你的PassthroughAsync的代码,但带有async/await:
async Task
然后,我们可以通过编译和反编译IL来看到巨大但完全多余的代码:
[AsyncStateMachine(typeof(
private Task
{
AsyncTaskMethodBuilder
<>t__builder.Start(ref
return
}
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct
{
public int <>1__state;
public AsyncTaskMethodBuilder
public C <>4__this;
public int x;
private TaskAwaiter
private void MoveNext()
{
int num = <>1__state;
C c = <>4__this;
string result;
try
{
TaskAwaiter
if (num != 0)
{
awaiter = c.DoSomethingPrettyAsync(x).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(TaskAwaiter
num = (<>1__state = -1);
}
result = awaiter.GetResult();
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
与非async passthru编译为的代码进行对比:
private Task
{
return DoSomethingPrettyAsync(x);
}
除了绕过大量的结构初始化和方法调用之外,如果实际上是异步的(在已同步完成的情况下不会“box”到堆上),这个PassthroughAsync还是一个很好的JIT内联候选对象,所以在实际的CPU操作码中,PassthroughAsync可能甚至不存在。