C#多线程技术总结(异步)
我這里針對現有的C#多線程技術進行一個匯總,一是復習,二是方便索引,文章部份知識點來源于網絡,非本人原創。
一、并行(異步):
1.System.Threading.Tasks命名空間下的(TPL):
1.1:Parallel.Invoke --并行執行多個任務,主線程等待并行執行完畢后才開始續續運行。
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | static?void?Main(string[] args) { ????Parallel.Invoke(new?ParallelOptions() { MaxDegreeOfParallelism=2},Run1,Run2); ????Console.WriteLine("我是主線程!"); ????Console.Read(); } static?void?Run1() { ????Console.WriteLine("我是任務一,我運行3s"); ????Thread.Sleep(3000); ????Console.WriteLine("任務一執先完成"); } static?void?Run2() { ????Console.WriteLine("我是任務二,我運行5s"); ????Thread.Sleep(5000); ????Console.WriteLine("任務二執先完成"); } |
1.2:Parallel.For--循環迭代多個任務,多個任務之間存在并行情況,主線程等待循環迭代的多個任務執行完畢后才開始續續運行。
示例:
| 1 2 3 4 5 | Parallel.For(0, 10, (i) => { ????????????????Console.WriteLine("我是第{0}個任務,線程ID是:{1}",i,Thread.CurrentThread.ManagedThreadId); ????????????????Thread.Sleep(new?Random().Next(10) * 10 * 500); ????????????????Console.WriteLine("線程ID是:{0}執行完成", Thread.CurrentThread.ManagedThreadId); ????????????}); |
1.3:Parallel.ForEach--循環迭代多個任務,多個任務之間存在并行情況,主線程等待循環迭代的多個任務執行完畢后才開始續續運行。注意它有多個重載方法
示例:
| 1 2 3 4 5 6 7 8 9 10 11 | var?bag =?new?ConcurrentBag<int>(); Parallel.ForEach(Partitioner.Create(0, 100), i => { ????for?(int?m = i.Item1; m < i.Item2; m++) ????{ ????????bag.Add(m); ????????Console.WriteLine("我是第{0}個任務,線程ID是:{1}", m, Thread.CurrentThread.ManagedThreadId); ????} }); Console.WriteLine("并行計算:集合有:{0}", bag.Count); |
1.4:TAP(基于任務的異步編),使用Task類 (注意:默認任務開啟后,會在新線程中執行,主線程不會等待任務而是繼續下面的執行,若使用Task.WaitAll,則會等待相應的任務完成后才會執行)
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //第一種方式啟動 var?task1 =?new?Task(() =>?//實例化 ????????????{ ????????????????Run1(); ????????????}); task1.Start();?//啟動 ?//第二種方式開啟 ?var?task2 = Task.Factory.StartNew(() =>?//直接創建任務并啟動 ????????????{ ????????????????Run2(); ????????????}); //主線程等待任務執行完 ?Task.WaitAll(task1, task2); |
2.ParallelEnumerable類中的擴展方法(先將枚舉對象使用AsParallel轉換成ParallelQuery類型,然后就可以使用ParallelQuery在ParallelEnumerable類相關的擴展方法)
示例:
| 1 2 | var?resultList = testList.AsParallel().Where(i=>i>=100).ToList(); ?Console.WriteLine("resultList Count:{0}", resultList.Count); |
3.創建新Thread--新線程啟動后,主線程與創建的線程各自執行,若需要主線程等待異步線程執行完成后才執行,則應使用asyncThread.Join方法。
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ????????static?void?AsyncThreadMethod() ????????{ ????????????Console.WriteLine("我是異步執行線程,線程ID是:{0}", Thread.CurrentThread.ManagedThreadId); ????????} ????????static?void?AsyncThreadMethod(object?state) ????????{ ????????????Console.WriteLine("我是異步執行線程,線程ID是:{0},狀態:{1}", Thread.CurrentThread.ManagedThreadId,state); ????????} //創建線程并執行 ????????????Thread asyncThread =?new?Thread(new?ThreadStart(AsyncThreadMethod)); ????????????asyncThread.IsBackground =?true; ????????????asyncThread.Start(); ????????????Thread asyncThread2 =?new?Thread(new?ParameterizedThreadStart(AsyncThreadMethod)); ????????????asyncThread2.IsBackground =?true; ????????????asyncThread2.Start("這是來自主線程的參數"); |
4.使用ThreadPool.QueueUserWorkItem靜態方法--WaitCallback回調方法要求其必需帶一個object的參數
示例:
| 1 2 3 | ThreadPool.QueueUserWorkItem(new?WaitCallback(AsyncThreadMethod));//不帶參數,則系統將state自動設為null ThreadPool.QueueUserWorkItem(new?WaitCallback(AsyncThreadMethod),?"這是來自主線程的參數"); |
5.APM(異步編程模型),利用BeginInvoke與EndInvoke完成異步執行委托方法
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Func<string,?string> funcDelegate = (s) => { ????Console.WriteLine("我是Func委托方法!"); ????return?"委托方法參數:"?+ s; }; //1.無阻塞異步回調 var?aysncResult = funcDelegate.BeginInvoke("這是來自主線程的參數",?new?AsyncCallback((result) => { ????//獲取委托對象,調用EndInvoke方法獲取運行結果 ????AsyncResult _result = (AsyncResult)result; ????var?func = (Func<string,?string>)_result.AsyncDelegate; ????string?data = func.EndInvoke(_result); ????Console.WriteLine(data +",附加參數:"?+ _result.AsyncState.ToString()); }),"其它參數"); //2.阻塞主線程,使主線程等待執行完畢 string?data2 =?null; var?aysncResult2 = funcDelegate.BeginInvoke("這是來自主線程的參數2",?null,?null); data2 = funcDelegate.EndInvoke(aysncResult2);//第一種阻塞方法 while?(!aysncResult2.IsCompleted)?//第二種阻塞方法 { ????Thread.Sleep(200);??????//虛擬操作 ????Console.WriteLine("主線程等待..."); } data2 = funcDelegate.EndInvoke(aysncResult2); WaitHandle[] waitHandles =?new?WaitHandle[]{ aysncResult2.AsyncWaitHandle }; while?(WaitHandle.WaitAll(waitHandles, 5000))?//第三種阻塞方法 { ????Console.WriteLine("主線程等待..."); } |
6. EAP(基于事件的異步編程)--主要用在客戶端應用程序中
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //例子一 var?client =?new?WebClient(); client.DownloadProgressChanged +=?delegate(object?s, DownloadProgressChangedEventArgs e) { ????Console.WriteLine("Download Percent:{0}", e.ProgressPercentage); }; client.DownloadStringCompleted +=?delegate(object?s,DownloadStringCompletedEventArgs e){ ????Console.WriteLine("Download Content Length:{0}",e.Result.Length); ????Console.WriteLine("Download Completed!"); }; client.DownloadStringAsync(new?Uri("http://www.zuowenjun.cn")); //例子二 BackgroundWorker worker =?new?BackgroundWorker(); worker.DoWork += (s, e) => { ????Console.WriteLine("異步執行中。。。"); }; worker.RunWorkerCompleted += (s, e) => { ????Console.WriteLine("異步執行完成。。。"); }; worker.RunWorkerAsync(); |
7.async和await關鍵字
示例:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ????public?Task<double> GetValueAsync(double?num1,?double?num2) ????{ ????????return?Task.Run(() => ????????{ ????????????for?(int?i = 0; i < 1000000; i++) ????????????{ ????????????????num1 = num1 / num2; ????????????} ????????????return?num1; ????????}); ????} ????public?async?void?DisplayValue() ????{ ????????double?result = await GetValueAsync(1234.5, 1.01);//此處會開新線程處理GetValueAsync任務,然后方法馬上返回 ????????//這之后的所有代碼都會被封裝成委托,在GetValueAsync任務完成時調用 ????????System.Diagnostics.Debug.WriteLine("Value is : "?+ result); ????} //調用 DisplayValue();//不會阻塞主線程 |
?參考以下相關文章:
C#綜合揭秘——細說多線程(上)
C#綜合揭秘——細說多線程(下)
8天玩轉并行開發系列文章
.NET基礎拾遺(5)多線程開發基礎
轉載于:https://www.cnblogs.com/wzg168/p/8559500.html
總結
以上是生活随笔為你收集整理的C#多线程技术总结(异步)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go语言入门——Go语言环境搭建
- 下一篇: 修改maven打包名字