async真的能让呼叫者等待吗?

时间:2016-03-10 20:37:31

标签: c# async-await

MSDN says

  

如果通过使用Async或async修饰符指定方法是异步方法,则启用以下两个功能...标记的异步方法本身可以通过调用它的方法等待。

但是another page gives this example

var originalWhen = $routeProvider.when;

$routeProvider.when = function(path, route) {
  if (!route.resolve) {
    route.resolve = {};
  }
  angular.extend(route.resolve, {
    availableCodes: function($rootScope, serverService) {
      if ($rootScope.isAuthenticated) {
        return numbersService.getAvailableCodes().$promise.then(function(data) {
          $rootScope.availableCodes = data.codes;
        });
      }
    }
  });
  return originalWhen.call($routeProvider, path, route);
};

在这里,我们看到它调用函数private async Task SumPageSizesAsync() { // To use the HttpClient type in desktop apps, you must include a using directive and add a // reference for the System.Net.Http namespace. HttpClient client = new HttpClient(); // . . . Task<byte[]> getContentsTask = client.GetByteArrayAsync(url); byte[] urlContents = await getContentsTask; // Equivalently, now that you see how it works, you can write the same thing in a single line. //byte[] urlContents = await client.GetByteArrayAsync(url); // . . . } not equipped with the async keyword,但调用者能够等待结果。

  1. 当MSDN说async修饰符允许呼叫者等待时,MSDN是否错误?
  2. 从调用者的角度来看,返回GetByteArrayAsync的函数与标记为异步的相同函数之间的区别是什么?

5 个答案:

答案 0 :(得分:4)

  

当MSDN说async修饰符允许调用者等待时,MSDN是否错误?

没有。它允许调用者等待重写您的方法以返回Task / Task<T>。但这不是唯一的方法。 任何返回等待的方法(例如Task<bool>YieldAwaitable)都可以让来电者等待

  

从调用者的角度来看,返回Task<T>的函数与标记为async的函数之间的区别是什么?

如果正确实施,应该没有任何区别。 asyncawait关键字是编译器帮助您编写异步代码的一种方式。但他们没有必要。你可以(而且你总是可以)在没有它们的情况下编写异步代码。

Task.Delay为例。它创建一个任务,设置一个计时器,配置计时器以在一段时间后完成任务并返回任务。它不使用async-await,也不需要。但是通过返回任务,它允许调用者等待它。

实际上,.NET框架中的许多任务返回方法都没有在内部使用async-await,因为它们是“根”异步方法。他们返回任务但没有任务等待自己。

答案 1 :(得分:3)

请勿等待函数,等待TaskTask<T>函数返回 1 。在您看到await client.GetByteArrayAsync(url)的任何示例中,隐藏的隐式Task<byte[]>会在client.GetByteArrayAsync(url)await之间“传递”。

你的问题类似于问“+在你做什么时如何工作

int result = 1 + 2;

vs你做什么

int two = 2;
int result = 1 + two;

文档说明它是为了将两个数字加在一起,但我没有在第二个例子中添加两个数字我正在添加数字和变量。“

1:它比这更完整,但99%的时间只是这样想。

答案 2 :(得分:2)

来自async/await faq(强调我的):

  

“async”关键字在应用于方法时的作用是什么?

     

当您使用“async”关键字标记方法时,您真的在说   编译器有两件事:

     
      
  1. 您告诉编译器您希望能够在方法中使用“await”关键字(您可以使用await关键字if   并且只有当它所在的方法或lambda被标记为async时)。这样做   所以,你告诉编译器使用状态编译方法   机器,这样该方法就可以暂停然后恢复   在等待点异步。
  2.   
  3. 您告诉编译器“解除”方法的结果或可能出现在返回类型中的任何异常。对于一种方法   返回任务或任务,这意味着任何返回的值或   在方法中未处理的异常存储在   结果任务。对于返回void的方法,这意味着任何   异常通过任何方式传播到调用者的上下文   “SynchronizationContext”在方法时是最新的   初始调用。
  4.   

因此,将它视为普通旧异步.NET模型的语法糖:更多的编译器检查,更少的代码,以及对调用者的角度完全无动于衷(调用者要么在async方法中等待结果,要么使用其他方法TPL原语,甚至是块。)

实际上,如果您选中source code of the GetByteArrayAsync method,它只是GetContentAsync方法的一个包装器,用TaskTaskCompletionSource构造结果private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func<HttpContent, Task<T>> readAs) { TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(); GetAsync(requestUri, completionOption).ContinueWithStandard(requestTask => { if (HandleRequestFaultsAndCancelation(requestTask, tcs)) { return; } HttpResponseMessage response = requestTask.Result; if (response.Content == null) { tcs.TrySetResult(defaultValue); return; } try { readAs(response.Content).ContinueWithStandard(contentTask => { if (!HttpUtilities.HandleFaultsAndCancelation(contentTask, tcs)) { tcs.TrySetResult(contentTask.Result); } }); } catch (Exception ex) { tcs.TrySetException(ex); } }); return tcs.Task; } 并继续传递样式。

{{1}}

答案 3 :(得分:1)

async修饰符可让您在该方法中使用await关键字 。在标记为Task的方法中,可以等待任何async - Task表示正在进行的活动,该活动在返回给调用方时可能已经完成,也可能尚未完成。

答案 4 :(得分:-1)

据我所知,等待 等待。 C是。

Task - 用于方法。 The marked async method can itself be awaited并不需要为了等待(这是您在Task中所做的事情)。

这也回答了第2部分 - 不同之处在于,无法等待返回await getContentsTask并且标记为Task的那个。这是MSDN在引用文中所说的内容。

(当然,我可能错了。)