基於任務的非同步程式設計(Task,async,await)
這節講一下比較高階的非同步程式設計用法Task,以及兩個非同步關鍵字async和await。
Task是在C#5.0推出的語法,它是基於任務的非同步程式設計語法,是對Thread的升級,也提供了很多API,先看一下Task怎麼使用:
System.Threading.Tasks.Task.Run(() => { Console.WriteLine("非同步"); }); System.Threading.Tasks.Task aTask=new System.Threading.Tasks.Task(() => { Console.WriteLine("非同步"); }); aTask.Start(); System.Threading.Tasks.Task.Factory.StartNew(() => { Console.WriteLine("非同步"); });
Task.Run()可以直接非同步執行一個方法,或者使用例項化Task傳入委託的方式,通過start()進行啟動,再或者使用Task.Factory.StartNew()直接啟動。
async,await
為了進一步介紹Task,需要先介紹兩個非同步有關的關鍵字async,await
async用在方法的宣告,await用於程式碼語句中。被async標記的方法,稱作非同步方法。但是,並非整個方法都是非同步執行,程式碼中以await開頭標記的程式碼,才是要真正非同步執行的具體內容。這個關鍵字一般是配合Task來使用的,Task有泛型的形式,標識非同步的返回值型別,通過Result()方法獲取返回值。這段說明很難理解,下面看程式碼演示:
static void Main(string[] args) { Console.WriteLine("新建一個非同步任務"); Task<int> task = new Program().GetValue(); Console.WriteLine("正在計算結果...."); Console.WriteLine($"執行結果為:{task.Result}"); Console.WriteLine("任務完成...."); } public async Task<int> GetValue() { Console.WriteLine("即將開始進行計算...3"); Console.WriteLine("即將開始進行計算...2"); Console.WriteLine("即將開始進行計算...1"); int a= await System.Threading.Tasks.Task.Run(() => { int i = 0; for (; i < 10; i++) { Console.WriteLine(i); } return i; }); Console.WriteLine("結果計算完成...."); return a; }
執行結果為:
從執行結果可以看出,程式執行到15行await處後,下一步就跳出了這個方法,回到第6行執行,這也是await的一個特性,非同步執行,將主執行緒執行權交回,也就是說,從15行到25行是在後臺執行緒中執行的,之前的執行都是同步的,之後的執行也是同步的,而且,主執行緒的腳步沒有停下,直到遇到task.Result,Result裡邊存放著非同步方法執行的返回值,執行到這,如果非同步沒有完成,就會阻塞當前執行緒,直到非同步返回結果。
另外說一點,之前在講自定義中介軟體的時候,涉及到過這兩個關鍵詞,現在明白了這個用法,可以回去再看一下,應該會對中介軟體的訪問流程有一個更清晰的理解。
ContinueWith
ContinueWith設定Task在執行完原有任務後,再繼續執行此方法設定的方法,下面看程式碼:
task.ContinueWith((task) => { Console.WriteLine("---------------"+a.Result); });
這是其中的一個過載,接受一個Action<Task<T>>型別的委託,此處乍一看可能會不解,其實就是把當前執行任務的Task物件傳進來了。這樣的用法有什麼好處呢,執行完了以後,可以直接取Task任務的返回值,不用阻塞執行緒,當然這是在返回值不是急需的情況下。
CancellationTokenSource
CancellationTokenSource類用於終止一個任務,請先看一下程式碼:
static void Main(string[] args) { CancellationTokenSource cancellationToken=new CancellationTokenSource(); Task<int> task= new Program().GetValue(cancellationToken); cancellationToken.Cancel(); Console.WriteLine("正在計算結果...."); Console.WriteLine($"執行結果為:{task.Result}"); Thread.Sleep(1000); Console.WriteLine("任務完成...."); } public Task<int> GetValue(CancellationTokenSource cancellationToken) { Task<int> a = System.Threading.Tasks.Task.Run(() => { int i = 0; for (; i < 100; i++) { Console.WriteLine(i); Thread.Sleep(500); } return i; },cancellationToken.Token); Console.WriteLine("結果計算完成...."); return a; }
建立一個CancellationTokenSource物件,在Run任務的時候傳入一個Token,就能呼叫Cancel()方法就能終止這個任務,執行結果為:
可以看到報錯了,這很正常,因為任務停止了,顯然Result是沒有值的
最後注意一點,非同步不是多執行緒,可以說非同步是基於多執行緒,但是它們不是等於的關係。
這是我的公眾號二維碼,獲取最新文章,請關注此號