1

我浏览了一个 msdn 示例代码,其中单击按钮时调用函数,调用例程时使用 Await 关键字,并且函数使用了 async 关键字。

private async void StartButton_Click(object sender, RoutedEventArgs e)
        {

            int contentLength = await AccessTheWebAsync();

            resultsTextBox.Text +=
                String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
        }

async Task<int> AccessTheWebAsync()
        { 
            HttpClient client = new HttpClient();
            Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
            DoIndependentWork();
            string urlContents = await getStringTask;

            return urlContents.Length;
        }


        void DoIndependentWork()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
  1. AccessTheWebAsync被调用然后使用await关键字,这是什么意思?
  2. 当这个函数 AccessTheWebAsync() 将被执行时,DoIndependentWork()函数会被调用,我猜这里的控制会一直等到这个函数DoIndependentWork()完成。我对吗?

还有另一个语句叫做

string urlContents = await getStringTask;

为什么他们在这里使用等待。如果我们不在这里使用 await 那么会发生什么?

请指导我了解它是如何工作的代码。

4

5 回答 5

3

我在这里有一篇介绍性博文,而且MSDN 文档也非常好。

您可以await将方法视为“暂停”方法(阻塞线程),直到等待操作完成。发生这种情况时,它会将未完成的任务返回给调用方法,因此它也可以选择await.

于 2013-11-12T12:38:26.510 回答
2

这是关于 async/await 方法的简要说明。

异步方法:

  • 调用者不一定会因为异步方法的完整执行而被阻止
  • 可能的返回类型
    • void: “一劳永逸”</li>
    • Task: 允许等待异步方法的终止
    • Task<T>: 允许等待终止并获得 T 类型的结果
  • 异步方法没有 ref 或 out 参数
  • 必须再次包含等待 => 否则编译警告

等待任务

  • 等待 TPL 任务的终止
  • 返回任务的结果(如果任务具有结果类型)
  • 只能出现在异步方法中 => 否则编译错误

异步方法是部分同步和部分异步的

  • 调用者同步执行方法,直到阻塞等待
  • 此后,方法rest被异步执行 async & await 机制高效
public async Task<int> GetSiteLengthAsync(string url) 
{  
    HttpClient client = new HttpClient();               <= Sync  
    Task<string> download1 = client.GetStringAsync(url); <= Sync  
    string site1 = await download1;   <= Async (Another thread)
    return site1.Length;              <= Async (Another thread)
}
于 2013-11-12T13:26:40.773 回答
1

await 所做的只是阻塞线程,直到异步操作的结果返回。

编辑:对不起,当我说阻塞时,我应该说暂停,因为阻塞会阻止执行继续!

Edit2:正如亚历克斯指出的那样——我应该说“执行被暂停”而不是线程。基本上“事情会发生,直到等待返回,但关键是您似乎正在编写和执行同步代码”

由于异步操作可能需要一段时间(例如 Web 服务调用),它们倾向于使用回调来返回结果。

如果您必须在代码中处理回调,它可能会有点混乱,尤其是在等待多个相互依赖的异步任务时。Async/await 和 Task 简化了代码,以便您可以按照阅读顺序逐字编写异步代码。

例如带有回调的示例标准异步代码:

public int CallSomeServiceAndReturnItsValue()   
{
    int result = 0;

    WebService.SomeAsyncServiceCall((svcResult) => { result = svcResult.Value; });

    return result;
}

如果您有多个需要链接的调用:

public int CallSomeServiceAndReturnItsValue()   
{
    int result = 0;

    WebService.GetSomeIdentifier((svcResult) => 
    {
         var identifier = svcResult.Value; 

         WebService.GetResult(identifier, (anotherResult) =>
            {
              result = anotherResult.Value;
            }
       }
    );

    return result;
}

如您所见,它开始变得混乱,代码并没有真正按照感觉自然的顺序阅读。另一种方法是使用回调方法而不是匿名方法,但回调方法与调用它们的代码相距甚远,而且事情可能会脱节

另一种选择当然是 async/await 更清晰

public int CallSomeServiceAndReturnItsValue()   
{
    int identifier = await WebService.GetSomeIdentifier();
    return await WebService.GetResult(identifier);
}
于 2013-11-12T12:39:42.410 回答
1

来自 MSDN:

await 运算符应用于异步方法中的任务,以暂停该方法的执行,直到等待的任务完成。该任务代表正在进行的工作。await 不会阻塞它正在执行的线程。相反,它会导致编译器注册 async 方法的其余部分作为等待任务的延续。然后控制权返回给异步方法的调用者。当任务完成时,它调用它的继续,并且异步方法的执行从它停止的地方继续。

所以当编译器遇到

     int contentLength = await AccessTheWebAsync();

它等到 AccessTheWebAsync()任务完成

请看一下这个例子C# Async,Await

于 2013-11-12T12:38:36.673 回答
1

不确定您是否更容易通过以下方式理解这一点,但这就是它帮助我自己的方式

如您所见,AccessTheWebAsync回报Task<int>但不仅仅是int.

如果你在没有“await”的情况下调用它,你只会得到Task<int>对象作为它的结果。并且可以通过该任务(手动)做任何你想做的事情:例如,等到它完成theTask.Wait();并获得intin的结果theTask.Result

但是await所有这些都代替了你,并且只返回int: Task<int>=> int

就是这个。

于 2013-11-12T12:38:52.480 回答