我是否应该为每个返回Task的方法使用async/await

Rob*_*bba 15 c# async-await

假设我有一个C#控制器调用一些返回Task的任意函数(例如,因为它执行数据库事务).我应该总是使用异步和等待,还是应该只返回任务?

示例控制器:

public async Task<string> DoSomething() {
    return await SomeOtherFunctionThatReturnsATask();
}
Run Code Online (Sandbox Code Playgroud)

我应该把它改成:

public Task<string> DoSomething() {
    return SomeOtherFunctionThatReturnsATask();
}
Run Code Online (Sandbox Code Playgroud)

还是真的没关系?

Cod*_*lla 23

是的,您应该更改方法并删除async/await.该async关键字使编译器创建一个状态机,用于管理"等待"任务完成.当你等待这样的另一个函数时,你实际上创建了两个这样的状态机,这是不必要的.最好直接从第二个函数返回任务,并允许任务的最终使用者进行等待.

理解这一点的最好方法是编写一个小样本程序并对其进行反编译.确保您的反编译器向您显示所有编译器生成的内容(默认情况下隐藏了一些内容),您将能够看到所有内容.

这是一个简单的例子,我刚刚掀起并使用dotPeek进行反编译:

public Task<string> DoSomething()
{
  Class1.\u003CDoSomething\u003Ed__0 stateMachine;
  stateMachine.\u003C\u003E4__this = this;
  stateMachine.\u003C\u003Et__builder = AsyncTaskMethodBuilder<string>.Create();
  stateMachine.\u003C\u003E1__state = -1;
  stateMachine.\u003C\u003Et__builder.Start<Class1.\u003CDoSomething\u003Ed__0>(ref stateMachine);
  return stateMachine.\u003C\u003Et__builder.Task;
}

private Task<string> DoSomethingElse()
{
  return Task.FromResult<string>("test");
}
Run Code Online (Sandbox Code Playgroud)

你可以看到我所指的第一个状态机.它将无缘无故地做所有等待的工作,然后最终的消费者DoSomething()将重复同样的工作.实际上,只有await当方法中的其他代码需要返回任务的代码之后运行时,才应该真正使用关键字.因为该代码需要等待它在运行之前完成.

完整的反编译代码:http://pastebin.com/iJLAFdHZ

  • 这就是为什么人们不应该从问题的标题中提出问题正文中的另一个问题.;) (3认同)
  • @PanagiotisKanavos是的,对不起我正在回答他问题正文中的问题.我会编辑. (3认同)
  • 也许您的意思是“不,您不应该”吗?问题标题为“我应该对每种方法使用异步/等待”吗?而您的答案说不,不应该使用 (2认同)
  • 实际上,它不是`await`关键字,而是`async`关键字,它导致编译器创建状态机.在MSDN上,在[本文](https://msdn.microsoft.com/en-us/magazine/hh456402.aspx)中,请参阅`SimpleBodyAsync()`及其IL的说明. (2认同)