2016-03-10 30 views
2

MSDN says异步真的能让呼叫者等待吗?

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

another page gives this example

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); 
    // . . . 
} 

这里我们可以看到它调用一个函数GetByteArrayAsync这是not equipped with the async keyword,然而主叫方能够等待的结果。

  1. 是否MSDN错误,当它说async修饰符使呼叫者等待?
  2. 从呼叫者的角度来看,返回Task<T>的函数与标记为异步的函数之间有什么区别?

回答

3

千万不要等待一个功能,你等待一个TaskTask<T>一个函数返回。在任何示例中,您看到await client.GetByteArrayAsync(url)都有一个隐含的隐含Task<byte[]>,它在client.GetByteArrayAsync(url)await之间“通过”。

您的问题类似,问:“如何当你做

int result = 1 + 2; 

VS当你做

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

的文档指出这是两数相加在一起+工作,但我我在第二个例子中没有添加两个数字,我正在添加一个数字和一个变量。“


1:这是比多一点完成,但对于99%的时间只是觉得这样的说法。

+0

如何协调您的答案与MSDN的文档,它是异步修改器,使呼叫者等待? –

+0

因为如果你标记一个方法'async',你也必须改变它来返回一个'Task '而不是'T',否则代码将不能编译,返回一个Task的动作是允许调用者等待的,它实际上与async关键字无关,它只是新返回类型的副作用。 –

1

一个async修改,您可以使用该方法内await关键字。可以在标记为async的方法中等待任何Task - Task代表正在进行的活动,当它返回给调用者时可能已经完成或可能未完成。

4

是否MSDN错误,当它说async修饰符使呼叫者等待?

不,它允许呼叫者等待,因为它会重写您的方法以返回Task/Task<T>。但这不是唯一的方法。 任何返回可等待的方法(例如Task<bool>,YieldAwaitable)都可使呼叫者等待

从来电者的角度看,那是什么返回Task<T>功能,并标记为async相同功能的区别?

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

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

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

+0

但是,从异步方法中唯一允许的返回类型是Task和void,调用者不能等待'async void'。所以在我看来,async关键字不是让调用者等待的地方 - 重要的是返回类型,而不是async关键字。 –

+0

@ridiculous_fish async关键字使您的方法返回一个'Task' /'任务'。任务本身就是等待的事情。您可以返回没有这些关键字的任务。 – i3arnon

+0

@ridiculous_fish还有其他一些awaitables,比如'YieldAwaitable',你可以等待哪些不能用于异步方法,但是你可以直接返回它。你甚至可以创建自己的awaitables。 – i3arnon

-1

据我可以告诉它不是正在等待。 Task是。

The marked async method can itself be awaited - 这是方法。 A Task不需要为了等待(这就是你在做的await getContentsTask)。

这也回答了部分2 - 不同的是,返回Taskasync不能等待的人。这是MSDN在引用文字中所说的。

(我可能是错的,当然。)

+0

这是一条评论,而不是答案。 – i3arnon

+0

@ i3arnon为什么? OP错误地认为等待Task是等待创建它的方法。我告诉他这不是。 (或者,也许我错了,如果是这样 - 请告诉我什么。) – ispiro

+2

不..这是正确的。这仅仅是对这个问题的回答。这只是评论。 – i3arnon

2

async/await faq(重点煤矿):

是什么当应用于方法的“异步”的关键字吗?

当您标记的“异步”关键字的方法,你真的告诉 编译器两件事情:

  1. 你告诉编译器,你希望能够使用“等待“方法中的关键字(如果 只有当方法或lambda进入标记为async时,可以使用await关键字)。在做 所以,你告诉编译器使用状态 机器编译该方法,使得该方法将能够在等待点异步地暂停然后恢复 。
  2. 您正在告诉编译器将该方法的结果或可能出现的任何异常“提升”到返回类型中。对于 返回任务或任务的方法,这意味着在方法内未处理的任何返回值或 例外将存储到 结果任务中。对于返回void的方法,这意味着任何 异常都会通过任何 “SynchronizationContext”在方法的 初始调用时当前传播到调用方的上下文中。

所以,认为它是一个语法糖超过普通老式异步.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; 
    }