为什么我必须使用等待时使用异步?

时间:2017-03-06 11:37:40

标签: c# .net asynchronous async-await

我已经坚持这个问题一段时间了,并且没有真正找到任何有用的澄清,为什么会这样。

如果我有async方法,请执行以下操作:

public async Task<bool> MyMethod()
{
    // Some logic
    return true;
}

public async void MyMethod2()
{
    var status = MyMethod(); // Visual studio green lines this and recommends using await
}

如果我在这里使用await,那么异步方法的重点是什么? VS告诉我拨打async时,await无法使echo "<td>" .$news['<img src = "data:image/jpg;base64,'.base64_encode($img).'"/>']. "</td>";无用吗?这不会破坏将任务卸载到线程而不等待它完成的目的吗?

3 个答案:

答案 0 :(得分:24)

  

如果我在这里使用await,那么异步方法的重点是什么?

await不会阻止线程。 MyMethod2将同步运行,直到达到await表达式。然后MyMethod2暂停,直到等待的任务(MyMethod)完成为止。虽然MyMethod未完成,但控制权将返回MyMethod2的来电者。 await - 来电者将继续这样做

  

这不会让VS告诉我等待的异步没用吗?

async只是一个标志,表示在方法的某个地方,您有一个或多个等待&#39;。

  

这不会破坏将任务卸载到线程的目的   没有等待它完成?

如上所述,您不必等待任务完成。这里没有任何东西被阻止。

注意:要遵循框架命名标准,我建议您将Async后缀添加到异步方法名称。

答案 1 :(得分:17)

  

这不会破坏将任务卸载到线程而不等待它完成的目的吗?

是的,当然。但那不是await / async 的目的。目的是允许您编写使用异步操作而不浪费线程的同步代码,或者更一般地说,允许调用者对或多或少的异步操作进行控制。

基本思想是,只要你正确使用await和async,整个操作就会显得同步。这通常是件好事,因为你做的大部分事情都是同步的 - 比如,你不想在请求用户名之前创建用户。所以你会做这样的事情:

var name = await GetNameAsync();
var user = await RemoteService.CreateUserAsync(name);

这两个操作相互同步;第二个不会(并且不能!)在第一个之前发生。但它们(必然)与来电者不一致。一个典型的例子是Windows窗体应用程序。想象一下,你有一个按钮,点击处理程序包含上面的代码 - 所有代码都在UI线程上运行,但同时,当你await时,UI线程可以自由地执行其他任务(类似于在操作完成之前使用Application.DoEvents。)

同步代码更易于编写和理解,因此这使您可以获得异步操作的大部分好处,而无需使代码更难理解。并且你不会失去异步执行任务的能力,因为Task本身只是一个承诺,而你总是必须{{1它立刻。想象一下await需要花费很多时间,但与此同时,在完成之前你需要做一些CPU工作:

GetNameAsync

现在你的代码仍然是美妙的同步 - var nameTask = GetNameAsync(); for (int i = 0; i < 100; i++) Thread.Sleep(100); // Important busy-work! var name = await nameTask; var user = await RemoteService.CreateUserAsync(name); 是同步点 - 而你可以使用异步操作执行并行的其他事情。另一个典型的例子是并行触发多个异步请求,但保持代码与所有请求的完成同步:

await

这些任务是相互异步的,但不是他们的调用者,这仍然是美妙的同步。

我已经制作了一个(不完整的)networking sample,它以这种方式使用await。基本的想法是,虽然大多数代码在逻辑上是同步的(有一个协议要遵循 - 请求登录 - >验证登录 - >读取循环......;你甚至可以看到等待多个任务的部分并行),当你实际有CPU工作时,你只使用一个线程。 Await使得这几乎是微不足道的 - 使用continuation或旧的Begin / End异步模型做同样的事情将会更加痛苦,特别是在错误处理方面。 Await让它看起来很干净。

答案 2 :(得分:5)

异步方法不会在其他线程上自动执行。实际上,情况正好相反:async方法总是在调用线程中执行。 async表示这是一种可以屈服于异步操作的方法。这意味着它可以在等待其他执行完成时将控制权返回给调用者。因此,asnync方法是等待其他异步操作的方法。

由于你在MyMethod2中无所事事,async在这里毫无意义,所以你的编译器会警告你。

有趣的是,实施async方法的团队已经承认标记方法async并不是必需的,因为仅仅在方法体中使用await就足够了编译器将其识别为异步。添加了使用async关键字的要求,以避免对使用await作为变量名称的现有代码进行更改。