程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 等待所有或任意異步任務完成,以及異步任務完成時的處理方案,異步任務完成

等待所有或任意異步任務完成,以及異步任務完成時的處理方案,異步任務完成

編輯:C#入門知識

等待所有或任意異步任務完成,以及異步任務完成時的處理方案,異步任務完成


 

本篇體驗如何等待所有異步任務完成、等待任意一個異步任務完成,以及異步任務完成時的處理。

 

等待一組任務的完成使用Task.WhenAll方法。

 

Task task1 = Task.Delay(TimeSpan.FromSeconds(1));
Task task2 = Task.Delay(TimeSpan.FromSeconds(2));
Task task3 = Task.Delay(TimeSpan.FromSeconds(3));
await Task.WhenAll(task1, task2, task3);

 

如果所有任務的結果類型相同且全部完成,Task.WhenAll返回每個任務執行結果的數組。

 

Task task1 = Task.FromResult(1);
Task task2 = Task.FromResult(2);
Task task3 = Task.FromResult(3);
int[] results = await Task.WhenAll(task1, task2, task3);
foreach(var item in results)
{
    Console.WriteLine(item);
}

 

舉個例子,提供一個url的集合,要求根據這個url集合去遠程下載對應的內容,寫一個方法。

 

static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
    var httpClient = new HttpClient();
    //定義每一個ulr的使用方法
    var downloads = urls.Select(url => httpClient.GetStringAsync(url));
    //下載真正開始
    Task<string>[] downloadTasks = downloads.ToArray();
    //異步等待
    string[] hmtls = await Task.WhenAll(downloadTasks);
    return string.Concat(htmls);
}

 

如果在等待所有任務完成的過程中有異常發生怎麼辦呢?

 

如果想在等待過程中捕獲異常,那麼應該把WhenAll方法放在try語句塊中;如果想在所有任務完成後捕獲異常,那就應該把WhenAll方法返回的Task類型放在try語句塊中。

 

先模擬兩個異步異常。

 

static async Task ThrowNotImplementedExceptionAsync()
{
    throw new NotImplementedException();
}
static async Task ThrowInvalidOperationExceptionAsync()
{
    throw new InvalidOperationException();
}

 

首先來看等待結果出來時的異常處理。

 

stati async Task ObserveOneExceptionAsync()
{
    var task1 = ThrowNotImplementedExceptionAsync();
    var task2 = ThrwoInvalidOperationExceptionAsync();
    try
    {
        await Task.WhenAll(task1, ask2);
    }
    cach(Exception ex)
    {
    }
}

 

再來看等所有結果出來後的異常處理。

 

static async Task ObserveAllExceptionAsync()
{
    var task1 = ThrowNotImplementedExceptionAsync();
    var task2 = ThrwoInvalidOperationExceptionAsync();
    Task allTasks = Task.WhenAll(task1, task2);
    try
    {
        await allTasks;
    }
    catch(Eexception ex)
    {
    }
}

 

等待任意一個任務的完成使用WhenAny方法。

 

比如有2個任務,通過2個url獲取異步遠程內容。

 

private static async Task<int> DownloadAsync(string url1, url2)
{
    var httpClient = new HttpClient();
    Task<byte[]> download1 = httpClient.GetByteArrayAsync(url1);
    Task<byte[]> download2 = httpClient.GetByteArrayAsync(url2);
    //等待任意一個任務完成
    Task<byte[]> completedTask = await Task.WhenAny(download1, download2);
    byte[] data = await completedTask;
    return data.Length;
}

 

任務完成時如何處理呢?

 

思路有2個,一個是根據我們安排的順序出結果,還有一個是根據任務本身出結果的先後順序自然輸出結果。

 

首先來一個異步方法。

 

static async Task<int> DelayAsync(int val)
{
    await Task.Delay(TimeSpan.FromSeconds(val));
    return val;
}

 

再寫一個手動部署任務順序的方法。

 

static async Task ProcessTasksAsync()
{
    //創建任務隊列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
    //手動安排任務的順序
    var tasks = new[]{task1, task2, task3};
    //按順序遍歷任務列表,逐一輸出結果
    foreach(var task in tasks)
    {
        var result = await task;
        Console.Write(result);
    }
}

 

輸出結果為231,是根據我們手動安排任務的順序輸出結果的。

 

如果我們想輸出123呢?即按照任務的不同讓結果自然發生。

 

思路是:以異步的方式處理輸出結果。

 

可以寫一個針對每個任務的異步方法。

 

static async Task AwaitAndProessAync(Task<int> task)
{
    var result = await task;
    Console.Write(result);
}

 

現在修改ProcessTasksAsync方法如下:

 

static async Task ProcessTasksAsync()
{
    //創建任務隊列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
    //手動安排任務的順序
    var tasks = new[]{task1, task2, task3};
    var processingTasks = (from t in tasks
                        select AwaitAndProessAync(t)).ToArray();
     await Task.WhenAll(processingTasks);                    
}

 

當然,也可以這樣修改ProcessTasksAsync方法。


static async Task ProcessTasksAsync()
{
    //創建任務隊列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
    //手動安排任務的順序
    var tasks = new[]{task1, task2, task3};
    var processingTasks = tasks.Select( async t => {
        var result = await t;
        Console.Write(result);
    }).ToArray();
                        
     await Task.WhenAll(processingTasks);                    
}

 

參考資料:C#並發編程經典實例

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved