簡體   English   中英

如何獲取異步代碼以等待所有任務完成?

[英]How do I get async code to wait until all tasks are complete?

當我運行下面的代碼時,在從HttpClient.GetAsync()調用返回結果之前,會出現消息"Press Enter to continue... " 實際的事件順序:進行GetAsync()調用,出現“ Press Enter... ”消息,然后將結果一一輸出到控制台窗口。 在顯示“ Press Enter... ”消息之前,如何等待直到所有GetAsync()調用完成?

class Program
{
  static HttpClient client = new HttpClient();

  static void Main(string[] args)
  {
    RunAsync().Wait();

    Console.WriteLine("\n\n\n\nPress Enter to continue... ");
    Console.ReadLine();
  }

  static async Task RunAsync()
  {
    List<string> urls = new List<string>()
    {
      "http://www.domain1.com",
      "http://www.domain2.com",
      "http://www.domain3.com",
      "http://www.domain4.com"
    };

    foreach (var url in urls)
    {
      DownloadPageAsync(url);
    }
  }

  static async Task<string> DownloadPageAsync(string url)
  {
    Console.WriteLine("Starting: " + url);

    HttpResponseMessage response = await client.GetAsync(url);

    if (response.IsSuccessStatusCode)
    {
      // do stuff here
    }

    Console.WriteLine("Done: " + url);

    return response.Content.ToString();
  }
}

由於DownloadPageAsync返回任務,因此您可以列出所有任務並等待所有任務:

Task.WhenAll(urls.Select(url => DownloadPageAsync(url)))

或簡化:

Task.WhenAll(urls.Select(DownloadPageAsync))

@ patrik-hofman的答案是一個很好的答案(已投票通過),請參閱我的評論

如果您希望請求按順序發生,請...在DownloadPageAsync行中添加await

您在RunAsync使用了async ,但是沒有await 因此,盡管它返回一個Task,但它並不等待DownloadPageAsync調用完成。 這意味着該方法僅返回立即完成的“空”任務。 因此,您的.Wait()沒有任何等待。

我認為問題在於您沒有等待RunAsync()方法中的DownloadPageAsync方法。 如果將RunAsync()方法更新為以下代碼,那么我相信它會按預期工作:

static async Task RunAsync()
{
    List<string> urls = new List<string>()
    {
      "http://www.domain1.com",
      "http://www.domain2.com",
      "http://www.domain3.com",
      "http://www.domain4.com"
    };

    foreach (var url in urls)
    {
        // added await here
        await DownloadPageAsync(url);
    }
}

您需要為每個所需的呼叫創建不同的任務,在您的示例中,您正在運行代碼而不等待呼叫。 當您調用WhenAll時,僅會為所有這些任務創建一個任務。 假設您使用下面的代碼,並且在每個MakeYouCall方法內部在列表中插入一個項目。 該列表將是您需要鎖定的共享資源。 當創建WhenAll時,如果您不等待結果(調用Wait()),則可以部分填充集合。

var register1 = new Action(() => MakeYourCall1());
var register2 = new Action(() => MakeYourCall2());
var register3 = new Action(() => MakeYourCall3());

然后

var t1 = Task.Factory.StartNew(register1);
var t2 = Task.Factory.StartNew(register2);
var t3 = Task.Factory.StartNew(register3);

之后,您可以調用WhenAll,它將返回一個Task,然后等待它。

Task.WhenAll(t1, t2, t3).Wait();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM