C#異步編程詳解。本站提示廣大學習愛好者:(C#異步編程詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C#異步編程詳解正文
前言
本節次要引見異步編程中Task、Async和Await的根底知識。
什麼是異步?
異步處置不必阻塞以後線程來等候處置完成,而是允許後續操作,直至其它線程將處置完成,並回調告訴此線程。
異步和多線程
相反點:防止調用線程阻塞,從而進步軟件的可呼應性。
不同點:
異步操作無須額定的線程擔負,並且運用回調的方式停止處置,在設計良好的狀況下,處置函數可以不用運用共享變量(即便無法完全不必,最最少可以增加 共享變量的數量),增加了死鎖的能夠。C#5.0 .NET4.5 當前關鍵字Async和Await的運用,使得異步編程變得異常復雜。
多線程中的處置順序仍然是順序執行,但是多線程的缺陷也異樣分明,線程的運用(濫用)會給零碎帶來上下文切換的額定擔負。並且線程間的共享變量能夠形成死鎖的呈現。
異步使用場景及原理
異步次要使用於IO操作,數據庫訪問,磁盤操作,Socket訪問、HTTP/TCP網絡通訊
緣由:關於IO操作並不需求CPU停止過多的計算,這些數據次要經過磁盤停止處置,假如停止同步通訊無法完畢,需求創立更多的線程資源,線程的數據上下文頻繁的切換也是對資源的糜費,針對IO操作不需求獨自的分配一個線程來處置。
舉例闡明:
操作:服務器接納HTTP懇求對數據庫停止操作然後前往
同步處置懇求的線程會被阻塞,異步處置懇求的線程不會阻塞。
義務
在運用義務之前,針對線程的調用大多都用線程池提供的靜態辦法QueueUserWorkItem,但是這個函數有很多的限制,其中最大的問題就是沒有外部機制可以讓開發者知道操作在什麼時分完成,也沒無機制在操作完成時獲取前往值,微軟為理解決這個問題引入了義務的概念。
首先結構一個Task<TResult>對象,並為TResult傳遞前往值,開端義務之後等候它並回去後果,示例代碼:
static void Main(string[] args) { Console.WriteLine("開端停止計算"); // ThreadPool.QueueUserWorkItem(Sum, 10); Task<int> task = new Task<int>(Sum, 100); task.Start(); //顯示等候獲取後果 task.Wait(); //調用Result時,等候前往後果 Console.WriteLine("順序後果為 Sum = {0}",task.Result); Console.WriteLine("順序完畢"); Console.ReadLine(); } public static int Sum(object i) { var sum = 0; for (var j = 0; j <= (int) i; j++) { Console.Write("{0} + ",sum); sum += j; } Console.WriteLine( " = {0}",sum); return sum; }
除了wait等候單個義務外,task還提供了等候多個義務,WaitAny和WaitAll,它阻止調用線程,直到數組中一切的Task對象完成。
取消義務
義務的取消異樣運用的是.NET Framework的規范取消操作形式,首先需求創立一個CancellationTokenSource對象,然後在函數中參加參數CancellationToken,將CancellationTokenSource的Token傳遞給辦法,然後調用IsCancellationRequested獲取能否曾經取消該值停止判別。
static void Main(string[] args) { Console.WriteLine("開端停止計算"); // ThreadPool.QueueUserWorkItem(Sum, 10); var ctx = new CancellationTokenSource(); var task = new Task<int>(() => Sum(ctx.Token, 100000)); task.Start(); //顯示等候獲取後果 //task.Wait(ctx.Token); Thread.Sleep(1000); ctx.Cancel(); //調用Result時,等候前往後果 Console.WriteLine("順序後果為 Sum = {0}", task.Result); Console.WriteLine("順序完畢"); Console.ReadLine(); } public static int Sum(CancellationToken cts, object i) { var sum = 0; for (var j = 0; j <= (int)i; j++) { if (cts.IsCancellationRequested) return sum; Thread.Sleep(50); Console.Write("{0} + ", sum); sum += j; } Console.WriteLine(" = {0}", sum); return sum; }
義務完成後自動啟動新義務
實踐的開發使用中,常常呈現一次義務完成後立即啟動另外一個義務,並且不可以使線程阻塞,在義務尚未完成時調用result會使順序阻塞,無法檢查義務的執行進度,TASK提供了一個辦法ContinueWith,它不會阻塞任何線程,當第一個義務完成時,會立刻啟動第二個義務。
static void Main(string[] args) { Console.WriteLine("開端停止計算"); // ThreadPool.QueueUserWorkItem(Sum, 10); var ctx = new CancellationTokenSource(); var task = new Task<int>(() => Sum(ctx.Token, 100000)); task.Start(); var cwt = task.ContinueWith(p => { Console.WriteLine("task result ={0} ",task.Result); }); //顯示等候獲取後果 //task.Wait(ctx.Token); Thread.Sleep(1000); ctx.Cancel(); //調用Result時,等候前往後果 Console.WriteLine("順序後果為 Sum = {0}", task.Result); Console.WriteLine("順序完畢"); Console.ReadLine(); } public static int Sum(CancellationToken cts, object i) { var sum = 0; for (var j = 0; j <= (int)i; j++) { if (cts.IsCancellationRequested) return sum; Thread.Sleep(50); Console.Write("{0} + ", sum); sum += j; } Console.WriteLine(" = {0}", sum); return sum; }
Async&Await 復雜運用
運用Async&Await的次要目的是方便停止異步操作,由於.net 4.0 以行進行異步操作時比擬復雜的,次要是經過調用微軟提供的異步回調辦法停止編程,假如遇到需求自己完成的辦法顯得十分頭疼,.net的各個版本都有自己主推的技術,像.NET1.1中的委托,.NET2.0中的泛型,.NET3.0中的Linq,.NET4.0中的Dynimac,.net4.5主推的就是異步編程,大家只需求理解TASK+異步函數就可以完成異步編程。
async:通知CLR這是一個異步函數。
await:將Task<TResult>前往值的函數停止異步處置。
示例目的:獲取網址JS代碼,並在界面顯示。
private static async Task<string> DownloadStringWithRetries(string uri) { using (var client = new HttpClient()) { // 第1 次重試前等1 秒,第2 次等2 秒,第3 次等4 秒。 var nextDelay = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { return await client.GetStringAsync(uri); } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 最後重試一次,以便讓調用者知道出錯信息。 return await client.GetStringAsync(uri); } }
static void Main(string[] args) { Console.WriteLine("獲取百度數據"); ExecuteAsync(); Console.WriteLine("線程完畢"); Console.ReadLine(); } public static async void ExecuteAsync() { string text = await DownloadStringWithRetries("http://wwww.baidu.com"); Console.WriteLine(text); }
運轉後果發現,首先獲取百度數據,線程完畢,最後顯示HTML代碼,這是由於異步開啟了新的線程,並不會形成線程阻塞。
以上就是本文的全部內容,希望本文的內容對大家的學習或許任務能帶來一定的協助,同時也希望多多支持!