使用 async 和 await 回调

Callback with async and await

我对异步作业的执行顺序有疑问。

我会用例子问我的问题,因为这样更容易理解。

这是来自 https://msdn.microsoft.com/en-us/library/mt674882.aspx 的官方示例,但有一些改动。

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

    //async operation:
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoWork1();

    // The await operator suspends AccessTheWebAsync.
    string urlContents = await getStringTask;

    DoWork2();

    return urlContents.Length;
}

我可以说 DoWork2client.GetStringAsync 的回调吗?

如果是这样,DoWork2 不会在 client.GetStringAsync 完成后立即执行 IF DoWork1 运行的时间比 client.GetStringAsync 长。

我在这儿吗?

DoWork2 is not immediately executed following the completion of client.GetStringAsync if DoWork1 runs longer time than client.GetStringAsync

一旦你达到那个点 await client.GetStrinkAsyncDoWork1() 已经完成,从你的例子来看它的执行是同步的。 client.GetStringAsync 完成后,DoWork2 将被设置为执行。

执行流程将是:

  1. GetStringAsync 异步启动。它会一直执行,直到它遇到第一个内部 await,然后将控制权交还给 AccessTheWebAsync.
  2. DoWork1()开始。因为它是同步的,所以每个人都在等待它完成
  3. client.GetStringAsync 异步等待 完成。 await 自然会将执行控制权交给它的调用者。
  4. 一旦client.GetStringAsync完成,执行将return到AccessTheWebAsyncDoWork2()将同步执行。
  5. urlContents.length 将被 return 编辑。

通常,第一个 await 关键字之后的所有内容都设置为方法其余部分的延续。

在:

//async operation:
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

您正在创建一个运行异步操作的任务,returns 立即发送给调用者,接下来 DoWork1() 同步执行,完成后 string urlContents = await getStringTask; 暂停方法的继续,直到等待的任务已经完成;一旦完成,程序将继续 DoWork2()

正确。

回答你的后续问题:

Is there a way to make the DoWork2 immediately executed once client.GetStringAsync is finished?

可能吧。这取决于这段代码的上下文。 DoWork1DoWork2 不可能同时在 UI 线程上 运行ning(显然,一个线程一次只能做一件事) .但是,如果这是从线程池上下文中调用的,那么可以肯定的是,可以同时 运行 它们。

但是,您应该将您的想法从"callback" 转变为"operation"。也就是说,不要将其视为 DoWork2GetStringAsync 的 "callback"。相反,可以这样想:我有一个操作 GetStringAsync,我有一个操作 DoWork2;我需要一个新的操作,先做一个再做另一个。

一旦你这样转变思路,解决方案就是为新的操作写一个方法:

async Task<string> GetStringAndDoWork2Async()
{
  HttpClient client = new HttpClient();
  var result = await client.GetStringAsync("http://msdn.microsoft.com");
  DoWork2();
  return result;
}

现在您可以在更高级别的方法中使用该新操作:

async Task<int> AccessTheWebAsync()
{
  var task = GetStringAndDoWork2Async();

  DoWork1();

  string urlContents = await task;

  return urlContents.Length;
}