C#线程模型脉络
今天在看同事新買到的《C#本質(zhì)論 Edition 4》的時(shí)候,對(duì)比下以前Edtion3的新特性時(shí),針對(duì)Async/Await關(guān)鍵字時(shí)發(fā)現(xiàn)對(duì)一些線程方面的定義還理解的不是很透徹,脈絡(luò)還不是很清晰,這樣有了本文,希望對(duì)有同樣困惑的朋友有些幫助。
??????文中部分內(nèi)容摘取自《Essential C# 5.0 Edition 4》,還有一些我個(gè)人的對(duì)線程方面知識(shí)的理解與概括,如果有錯(cuò)誤的地方還請(qǐng)指出,如果您覺(jué)得文章還不錯(cuò),請(qǐng)點(diǎn)擊“推薦” :)
C#線程模型脈絡(luò)
縮寫:
SPM:Synchronous Programming Mode,同步編程模型。
APM:Asynchronous Programming Mode,異步編程模型。(.Net 1.x的版本可以使用)
EAP:Event-Based Asynchronous Programming,基于事件的異步編程。(.Net Framework2.0中引入)
TAP:Task-Based Asynchronous Programming,基于任務(wù)的異步編程。(.Net Framework4.0中引入)
?
???????? C#的編程模型從SPM發(fā)展到APM編程模型,是Winform發(fā)展過(guò)程中解決界面由于同步執(zhí)行長(zhǎng)時(shí)間任務(wù)而導(dǎo)致界面“卡住”而發(fā)展而來(lái)(這里插一句個(gè)人對(duì)技術(shù)的理解:技術(shù)的發(fā)展總是在舊事物不能得到滿足的情況下發(fā)展而來(lái),新事物總是在特定的場(chǎng)合“出現(xiàn)”,并更好的代替了舊事物,所以,如果想了深入了解一個(gè)新事物的特性,必然要了解其發(fā)展脈絡(luò)以及適用的場(chǎng)景),有了異步編程模式之后,人們又開(kāi)始探索如何能更好的管理線程,更簡(jiǎn)單的適用,于是有了類似Background Worker和async/await一類的特性。
C#線程的編程模型到這里也就結(jié)束了,如果你有這方面的經(jīng)驗(yàn)可能都覺(jué)得以上都是“廢話”,或者“一言以概之”,的確,我不反對(duì),但是有時(shí)候?qū)懳恼掠行r(shí)候不僅僅是炫耀技術(shù),更多的是總結(jié)、歸納,理解的東西不一定說(shuō)的出來(lái),說(shuō)出來(lái)的東西不一定真正理解!
???????? 下面,針對(duì)每個(gè)內(nèi)容做一個(gè)小結(jié),老鳥(niǎo)飛過(guò):)
SPM同步編程模型
???????? Winform程序基于消息泵機(jī)制,依次執(zhí)行從“消息泵”中取出的數(shù)據(jù)”,當(dāng)某一消息需耗費(fèi)大量系統(tǒng)資源去執(zhí)行,則下一條消息不得不等待,這樣會(huì)造成程序界面“掛起”,這就是同步執(zhí)行任務(wù)的一種模型,當(dāng)然這只是同步模型下的一種劣勢(shì),其實(shí)現(xiàn)實(shí)中我們同步模型我們無(wú)時(shí)無(wú)刻不在用,包括編寫的代碼、執(zhí)行的業(yè)務(wù)邏輯等。
APM異步編程模型
???????? 為了解決同步模型中由于執(zhí)行耗時(shí)任務(wù)而不得不等待的問(wèn)題,產(chǎn)生了異步編程模式,其核心思想就是將耗時(shí)任務(wù)交付給其他“線程”去做,釋放主線程。這里多出兩句,在操作系統(tǒng)級(jí)別上Windows采用分時(shí)、多核以及多線程等技術(shù)來(lái)充分利用系統(tǒng)資源;在C#語(yǔ)言上由Thread發(fā)展到Task,Task是更高級(jí)的對(duì)Thread封裝,提升資源利用率,有了這些基礎(chǔ)才有更廣闊的空間。
BeginXXX和EndXXX
使用BeginXXX和EndXXX實(shí)現(xiàn)基本的異步模式。
?
class Program{static void Main(string[] args){string url = "http://www.cnblogs.com/cuiyansong/";if (args.Length > 0)url = args[0];Console.WriteLine(url);var webRequest = System.Net.WebRequest.Create(url);IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);while (!asyncResult.AsyncWaitHandle.WaitOne(200)){Console.WriteLine(".");}var webResponse = webRequest.EndGetResponse(asyncResult);using (System.IO.StreamReader reader = new System.IO.StreamReader(webResponse.GetResponseStream())){var bytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());int length = bytes.Length;Console.WriteLine(length);}Console.Read();}}?
TPL+APM模式
TPL:Task Parallel Library 任務(wù)并行庫(kù),其對(duì)task進(jìn)行擴(kuò)展,類似于ThreadPool。
這個(gè)模式是利用TaskFactory進(jìn)行并行計(jì)算(下載)的例子,這個(gè)例子很有意思,很復(fù)古的感覺(jué),有情趣的拷貝代碼看看運(yùn)行效果~~~
?
class Program{private static object ConsoleSyncObj = new object();static void Main(string[] args){string[] urls = args;if (args.Length == 0){urls = new string[]{"http://www.cnblogs.com/cuiyansong/","https://github.com/Cuiyansong","http://www.cnblogs.com/",};}Task[] tasks = new Task[urls.Length];for (int i = 0; i < tasks.Length; i++){tasks[i] = DisplayPageSizeAsync(urls[i], i);}while (!Task.WaitAll(tasks, 50)){DisplayProgress(tasks);}Console.SetCursorPosition(0, urls.Length);Console.Read();}private static void DisplayProgress(Task[] tasks){for (int i = 0; i < tasks.Length; i++){if (!tasks[i].IsCompleted){DisplayProgress((WebRequestState)tasks[i].AsyncState);}}}private static void DisplayProgress(WebRequestState state){lock (ConsoleSyncObj){int left = state.ConsoleColumn;int top = state.ConsoleLine;if (left > Console.BufferWidth - int.MaxValue.ToString().Length){left = state.Url.Length;Console.SetCursorPosition(left, top);Console.Write("".PadRight(Console.BufferWidth - state.Url.Length));state.ConsoleColumn = left;}Write(state, ".");}}private static string FormatBytes(long bytes){string[] magintudes = new string[] { "GB", "MB", "KB", "Bytes" };long max = (long)Math.Pow(1024, magintudes.Length);return string.Format("{1:##.##} {0}", magintudes.FirstOrDefault(mag => bytes > (max /= 1024)) ?? "0 Bytes", (decimal)bytes / (decimal)max).Trim();}private static Task<System.Net.WebResponse> DisplayPageSizeAsync(string url, int i){var webRequest = System.Net.WebRequest.Create(url);var requestState = new WebRequestState(webRequest, i);Write(requestState, url + " ");return Task<System.Net.WebResponse>.Factory.FromAsync(webRequest.BeginGetResponse, GetResponseAsyncCompleted, requestState);}private static WebResponse GetResponseAsyncCompleted(IAsyncResult asyncResult){WebRequestState completedState = (WebRequestState)asyncResult.AsyncState;HttpWebResponse response = (HttpWebResponse)completedState.WebRequest.EndGetResponse(asyncResult);using (StreamReader reader = new StreamReader(response.GetResponseStream())){int length = reader.ReadToEnd().Length;Write(completedState, FormatBytes(length));}return response;}private static void Write(WebRequestState completedState, string text){lock (ConsoleSyncObj){Console.SetCursorPosition(completedState.ConsoleColumn, completedState.ConsoleLine);Console.Write(text);completedState.ConsoleColumn += text.Length;}}private class WebRequestState{public System.Net.WebRequest WebRequest { get; private set; }public int ConsoleLine { get; set; }public int ConsoleColumn { get; set; }public string Url{get{return WebRequest.RequestUri.ToString();}}public WebRequestState(System.Net.WebRequest request){WebRequest = request;}public WebRequestState(System.Net.WebRequest request, int line){WebRequest = request;ConsoleLine = line;ConsoleColumn = 0;}}}?
BackgroundWorker模型
針對(duì)經(jīng)常出現(xiàn)任務(wù)委托后,執(zhí)行任務(wù)并返回進(jìn)度的需求,提供了BackgroundWorker類,節(jié)省開(kāi)發(fā)時(shí)間。
?
class Program{static void Main(string[] args){/****************************************************************************** 由于是演示,并為增加對(duì)BackgroundWorker取消等功能,這里只是簡(jiǎn)單演示。* 詳細(xì)請(qǐng)參考:http://www.cnblogs.com/RoyYu/archive/2011/08/10/2133309.html* ***************************************************************************/System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();worker.WorkerReportsProgress = true;//報(bào)告完成進(jìn)度worker.WorkerSupportsCancellation = true;//允許用戶終止后臺(tái)線程worker.DoWork += (sender, e) =>{for (int i = 0; i < 10; i++){System.Threading.Thread.Sleep(500);worker.ReportProgress(i, i);}};worker.ProgressChanged += (sender, e) =>{Console.WriteLine(string.Format("完成百分比。。。{0}", e.ProgressPercentage / (float)10));};worker.RunWorkerCompleted += (sender, e) =>{if (!e.Cancelled && e.Error == null){Console.WriteLine("處理成功,請(qǐng)按任意鍵返回。");}else{Console.WriteLine("處理中斷,請(qǐng)按任意鍵返回。");}};worker.RunWorkerAsync();Console.Read();}}Async/Await模型
這回用窗體程序進(jìn)行演示,對(duì)比起來(lái)效果會(huì)更明顯些。
public partial class MainWindow : Window{List<string> urls = new List<string>();public MainWindow(){InitializeComponent();urls = new List<string>(){"www.baidu.com","www.cnblogs.cn","www.stackoverflow.com",};}/// <summary>/// 同步執(zhí)行示例:當(dāng)點(diǎn)擊Button后,界面掛起,等待執(zhí)行完畢后顯示全部?jī)?nèi)容。/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Button_Click1(object sender, RoutedEventArgs e){InfoList.Text = "Ping....." + System.Environment.NewLine;Ping p = new Ping();foreach (var item in urls){PingReply pingRelay = p.Send(item);InfoList.Text += string.Format("Host Name: {0},Roundtrip Time: {1},Status: {2}", item, pingRelay.RoundtripTime.ToString(), pingRelay.Status + System.Environment.NewLine);}}/// <summary>/// 異步執(zhí)行示例:當(dāng)點(diǎn)擊Button后,界面不掛起,界面滾動(dòng)顯示信息。/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private async void Button_Click2(object sender, RoutedEventArgs e){InfoList.Text = "Ping....." + System.Environment.NewLine;Ping p = new Ping();foreach (var item in urls){PingReply pingRelay = await p.SendPingAsync(item);InfoList.Text += string.Format("Host Name: {0},Roundtrip Time: {1},Status: {2}", item, pingRelay.RoundtripTime.ToString(), pingRelay.Status + System.Environment.NewLine);}}}結(jié)語(yǔ)
下載源代碼,請(qǐng)點(diǎn)擊這里。
文章內(nèi)容確實(shí)不是很深入,但對(duì)理解Winform的異步線程模型還是很有幫助的,今后有時(shí)間會(huì)針對(duì)線程單獨(dú)來(lái)分享,希望各位看官不吝賜“贊”,水平有限,有問(wèn)題歡迎提問(wèn):)
引用
?
作者:Stephen Cui?
出處:http://www.cnblogs.com/cuiyansong?
版權(quán)聲明:文章屬于本人及博客園共有,凡是沒(méi)有標(biāo)注[轉(zhuǎn)載]的,請(qǐng)?jiān)谖恼履┪布尤胛业牟┛偷刂贰?
如果您覺(jué)得文章寫的還不錯(cuò),請(qǐng)點(diǎn)擊“推薦一下”,謝謝。
總結(jié)
- 上一篇: 美国“抗疫队长”也中招:福奇新冠病毒检测
- 下一篇: C#接口汇总