C#異步Task

C#異步Task

概述

異步是什麼?爲什麼需要異步?

  • 使用多線程的目的其實即使爲了實現異步+並行,異步:是相對同步的,同步就是一個流程安裝一個流程執行完畢,異步就是在不影響主流程的執行同時,可以執行其他流程,這也就是達到了幾個邏輯並行執行的效果。
  • 異步編程要解決的問題就是許多耗時的IO可能會阻塞線程導致CPU空轉降低效率,或者一個長時間的後臺任務會阻塞用戶界面。通過將耗時任務異步執行來使系統有更高的吞吐量,或保持界面的響應能力。
  • 同步/異步/阻塞/非阻塞/BIO/NIO/AIO 參考
    https://www.cnblogs.com/lixinjie/p/a-post-about-io-clearly.html
  • C# 中實現異步的方式有很多種,本文主要講解常用方案Task

基本語法

1. Task創建執行

   public static void TaskCreateRun() 
   {
       // 方式1: Task.Run
       Task.Run(() =>
       {
           MessageBox.Show("Task.Run");
       });

       // 方式2: Task.Factory.StartNew
       Task.Factory.StartNew(() =>
       {
           MessageBox.Show("Task.Factory.StartNew");
       });

       //方式3:new Task<返回類型>
       Task<int> t=new Task<int>(() => { MessageBox.Show("new Task"); return 1;});
       t.Start();
   }

2. Task異步方法

  • 使用async關鍵字標記,表示該方法可以包含異步操作。
  • 通常返回Task或Task類型,其中T是返回值類型。
  • 使用await或Result關鍵字暫停方法執行,直到等待的異步操作完成。
  • 使用await調用異步方法,方法定義必須添加async

方法定義:通常返回Task或Task類型,其中T是返回值類型

 public static async Task<string> GetStringAsync()
 {
     //方式1: 使用await的方法,方法定義必須添加async
     //return await Task.Run(() =>
     //{
     //    return "Task.FromResult 返回結果";
     //});

     //方式2: 使用Task.FromResult
     return await Task.FromResult("GetStringAsync Task.FromResult 返回結果");
 }

 public static Task<string> GetStringAsync2()
 {
     return  Task.FromResult("GetStringAsync2 Task.FromResult 返回結果");
 }

方法調用:使用await或result關鍵字暫停方法執行,獲取結果。 暫停多個異步方法 WaitAll、WaitAny、WhenAll。

 var r= GetStringAsync().Result;
 MessageBox.Show(await GetStringAsync2());
 GetStringAsync2().Wait();//同步,獲取不到返回值,只適合無返回值的方法
 //處理多個異步方法
 Task.WaitAll(GetStringAsync2(),GetStringAsync());//同步阻塞,所有執行完成。獲取不到返回值,只適合無返回值的方法。
Task.WaitAny(GetStringAsync2(),GetStringAsync());//同步阻塞,其中1個異步執行完成。獲取不到返回值,只適合無返回值的方法。
//同步阻塞,獲取到所有異步方法的返回值
Task.WhenAll(GetStringAsync2(), GetStringAsync()).ContinueWith(p => {
    p.Result.ToList().ForEach(t => MessageBox.Show(t));
});

注意事項

  • Task.Wait()和Task.Result 將異步轉爲同步,容易造成死鎖。儘量少使用。
  • 調用Task.WaitAll的時候,會阻塞當前線程,直到所有的Task都完成了。而Task.WhenAll方法不會阻塞當前線程,而是直接返回了一個Task,只有在讀取這個Task的Result的時候,纔會引起阻塞。

3. 取消異步執行CancellationTokenSource

static  CancellationTokenSource cts = new CancellationTokenSource();
static CancellationToken token = cts.Token;
 /// <summary>
 /// 取消異步方法
 /// </summary>
 public static void TaskCanceled() 
 {
     Task task = Task.Run(() =>
     {
         for (int i = 0; i < 10; i++)
         {
             if (token.IsCancellationRequested)
             {
                 MessageBox.Show("任務已取消");
                 return;
             }

             MessageBox.Show($"正在執行操作:{i}");
             Thread.Sleep(300);
         }

         MessageBox.Show("任務完成");
     }, token);
 }
//調用
    TaskCanceled();
    Thread.Sleep(3000);
    cts.Cancel();

4.Task並行數量控制LimitedConcurrencyLevelTaskScheduler

常見的應用場景

  • 耗時IO或三方服務:文件下載、日誌記錄、消息訂閱、郵件短信發送等。
  • Web服務器: Web 服務器通常使用多線程來處理多個客戶端的請求。每個請求都由一個單獨的線程處理,這樣可以避免單個請求阻塞其他請求。
  • 媒體播放器: 媒體播放器通常使用多線程來解碼音頻和視頻數據。解碼是一項耗時的操作,如果使用單線程進行解碼,則會阻塞播放。使用多線程可以將解碼和播放分開進行,從而提高播放的流暢性。
  • 遊戲: 遊戲通常使用多線程來渲染圖形、處理玩家輸入和更新遊戲狀態。這些任務都需要大量的 CPU 時間,使用多線程可以充分利用多核 CPU 的優勢,從而提高遊戲的性能。
  • 科學計算: 科學計算通常需要處理大量的數據,可以使用多線程來將計算任務分解成多個子任務,同時執行。這可以顯著提高計算效率。

總結

Task是C#中一種功能強大且易於使用的異步編程工具,它可以幫助我們開發更加響應、高效和易於維護的應用程序。

  • 1、Task的創建運行可以有三種方式:new Task/Task.Factory/Task.Run

  • 2、Task的返回參數定義Task<返回類型> 。獲取返回值:Task.Result->要阻塞主流程

  • 3、Task線程的同步實現不僅僅可以通過RunSynchronously來實現同步運行,當然還可以通過Task.Result/Task.Wait等方式來變向實現

  • 4、Task的wait/waitAll/waitAny實現阻塞等待執行結果

  • 5、Task的WhenAny、WhenAll、ContinueWith實現延續操作

  • 6、CancellationTokenSource實現異步任務取消

  • 7、異步方法之:(async/await)實現同步和異步調用等

引用

  1. 博文示例代碼 https://github.com/chi8708/DotNetNote/blob/master/Note.Basic/07Task.cs

  2. https://www.cnblogs.com/xiaoXuZhi/p/XYH_tsak_WhenAny1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章