在这里做什么呢?

时间:2019-02-11 12:55:45

标签: c# async-await

给出方法签名:

(awaitable) Task<Token> ITokenService.GetAPIToken();

在这种方法中,与await一起发生的事情是什么?

public async Task<User> GetUser(string userId)
{
    Token token = await TokenService.GetAPIToken();

    //..........
}

我的理解:调用GetAPIToken,当前方法(GetUser)返回一个Task<User>对象(提供一个User对象后来)。只有GetAPIToken方法返回后,当前方法的执行才会继续。

如果我错了,那么代码等待token方法返回时GetAPIToken()的类型/值是什么?

我知道调用此方法的结果会有所不同,因为可以使用或不使用await关键字来调用此方法。对于该帖子,请假定该帖子是通过await调用的。

2 个答案:

答案 0 :(得分:7)

  

我的理解:调用GetAPIToken,当前方法(GetUser)返回一个Task<User>对象(稍后将提供一个User对象)。只有GetAPIToken方法返回后,当前方法的执行才会继续。

那非常接近。让我们用两种方法来完善它。

首先,让我们区分 returns (这意味着将控制权返回给调用者)和 completes ,这意味着该方法所代表的任务已完成并且我们有它的价值,或者在异常完成的情况下有例外。

在非异步方法中,我们无需进行区分,因为仅在完成时才将控制权返回给调用方。在异步方法中,我们可以暂停返回(由于等待未完成的任务而调用方)或完成返回(当表示的任务被信号通知完成时)。

第二,用任务创建时完成的情况来表达工作流是有帮助的。例如,在缓存的情况下可能会发生这种情况。

现在让我们重新考虑一下您的理解:

  • GetAPIToken被调用并将任务返回给当前用户。
  • 如果任务已完成,则GetApiToken在完成所有工作后将返回。 GetUser从完成的任务中提取令牌,然后继续而不暂停。
  • 如果任务尚未完成,并且这是GetUser中的第一个等待,则GetUser将创建一个Task<User>
  • GetUserGetUser的其余部分分配为Task<Token>的延续,并通过返回Task<User>
  • 暂停
  • Task<Token>完成后,它将继续运行,并从中断的地方继续GetUser
  

当代码等待GetAPIToken()方法返回时,令牌的类型/值是什么?

那么,在等效的非异步情况下,token的值是什么?考虑:

Token x = Foo();

我们在等待Foo完成时x的值是多少?使Foo异步并没有什么不同;在呼叫正常完成之后,本地才会被分配值。如果Foo陷入无限循环,或者Foo抛出,则永远不会分配x

当然,在实践中,C#在创建所有本地变量时为其分配默认值,因此这就是变量中的值。

答案 1 :(得分:1)

在与await的行上,实际上GetUser()的执行已停止(唤醒),直到GetAPIToken()返回。这是对的。因此,token在返回GetAPIToken()之前没有任何价值(或者在这种情况下甚至被声明)。

GetUser()返回的内容取决于调用它的方式,带有或不带有await运算符。如果使用await进行了调用,则GetUser()的调用者也将等待它完成。同样在这种情况下,呼叫者最终将得到User返回的GetUser(),而不是Task<User>

在这种情况下,并行运行任何内容都不会使您受益。

如果另一方面,GetUser()是在没有await运算符的情况下被调用的,则发生了两种不同的情况:GetUser()早在实际到达您的线路时就返回到调用方;并在所有内容都未创建之后直接返回Task<User>而不是User

调用者可以稍后从此Task(在并行完成其他事情之后,这就是重点)得到结果User。这可以通过不同的方式来完成。请参阅Task<>的方法和属性。

了解并行运行的时间很重要。在这种情况下(如果在没有GetUser()的情况下调用await的情况下,有可能GetUser()返回并且您继续做事,而同时在另一个线程中GetAPIToken()还没有还没有返回,因此token未初始化。

使用图表检查此不错的MSDN文章: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index#BKMK_WhatHappensUnderstandinganAsyncMethod