多線程是一個不會過期的話題,由於每一個開發的成長必然要掌握這個知識點,不然半懂不懂怎麼保證系統的可靠性和性能,其實在網上隨便一搜都會有海量的文章說這個話題,大多數寫得很細寫得很是好,但發現不多有概覽性的文章,我但願能借本文給你們一個全局視野,結合多年實踐幫你們快速學習或者回顧思考,對感興趣的知識點再深刻學習瞭解。多線程
1、知識點歸納性能
2、具體實例演示如何實現學習
> Thread 多線程最基礎的類字體
//ThreadPool.GetMaxThreads(out int maxTCount, out int maxPCount); //ThreadPool.GetMinThreads(out int minTCount, out int minPCount); //ThreadPool.SetMaxThreads(maxTCount, maxPCount);// 調整最大線程數 //ThreadPool.SetMinThreads(minTCount, minPCount);// 調整最小線程數 long tick = C_ITEM_COUNT; ManualResetEvent signal = new ManualResetEvent(false); Console.WriteLine("========== 示例:採用Thread執行處理 =========="); for (int i = 0; i < C_ITEM_COUNT; i++) { new Thread((obj) => { Thread.Sleep(500); Console.Write(" {0} ", obj); if (Interlocked.Decrement(ref tick) == 0) signal.Set(); }).Start(i); } Console.Write(" 等待子線程執行 "); signal.WaitOne(); Console.WriteLine(); Console.WriteLine("所有線程執行完畢,按任意鍵繼續...");
> ThreadPool 線程池,XX池的概念能夠普遍應用於其餘資源管理,例如字體池(防句柄泄露)、短信貓池等等spa
tick = C_ITEM_COUNT; signal.Reset(); Console.WriteLine(); Console.WriteLine("========== 示例:採用ThreadPool執行處理 =========="); for (int i = 0; i < C_ITEM_COUNT; i++) { ThreadPool.QueueUserWorkItem((obj) => { Thread.Sleep(500); Console.Write(" {0} ", obj); if (Interlocked.Decrement(ref tick) == 0) signal.Set(); }, i); } Console.Write(" 等待子線程執行 "); signal.WaitOne(); Console.WriteLine(); Console.WriteLine("所有線程執行完畢,按任意鍵繼續...");
> Task 任務,功能豐富用法靈活。結合現實生活用字面意思去理解就好:能夠同時作多個任務,任務作完能夠接着作其餘任務,任務可能會取消等等。線程
tick = C_ITEM_COUNT; signal.Reset(); Console.WriteLine(); Console.WriteLine("========== 示例:採用Task執行處理,注意取消了處理{0}的進程 ==========", C_ITEM_COUNT - 2); var tasks = new Tuple<Task, CancellationTokenSource>[C_ITEM_COUNT]; for (int i = 0; i < C_ITEM_COUNT; i++) { var cts = new CancellationTokenSource(); var task = Task.Factory.StartNew((obj) => { Thread.Sleep(500); Console.Write(" {0} ", obj); }, i, cts.Token); task.ContinueWith((t) => { if (Interlocked.Decrement(ref tick) == 0) signal.Set(); }); tasks[i] = new Tuple<Task, CancellationTokenSource>(task, cts); } tasks[C_ITEM_COUNT - 2].Item2.Cancel();// 取消線程。 Console.Write(" 等待子線程執行 "); signal.WaitOne(); Console.WriteLine(); Console.WriteLine("所有線程執行完畢,按任意鍵繼續...");
> Parallel 並行3d
tick = C_ITEM_COUNT; signal.Reset(); Console.WriteLine(); Console.WriteLine("========== 示例:採用Parallel執行處理 =========="); Parallel.For(0, C_ITEM_COUNT, obj => { Thread.Sleep(500); Console.Write(" {0} ", obj); if (Interlocked.Decrement(ref tick) == 0) signal.Set(); }); Console.Write(" 等待子線程執行 "); signal.WaitOne(); Console.WriteLine(); Console.WriteLine("所有線程執行完畢,按任意鍵繼續...");
以上示例執行結果以下,重點能夠關注下"等待子線程執行"這個節點,理解主線程和各子線程的優先執行順序code
3、性能對比(理解線程池技術的性能也能夠經過最大最小線程數調節)blog
> 循環數:200,線程池參數:默認進程
> 循環數:200,線程池參數:50 - 1000
> 循環數200,線程池參數:100-1000
> 循環數200,線程池參數:200-1000
最大線程數 ~ 最小線程數 | Thread(ms) | ThreadPool(ms) | Task(ms) | Parallel(ms) |
2047/1000 ~ 12/12 | 2712.09 | 8057.14 | 8585.01 | 7526.57 |
1000/1000 ~ 50/50 | 2733.25 | 2289.96 | 2218.29 | 3660.33 |
1000/1000 ~ 100/100 | 2503.08 | 1620.73 | 1534.50 | 1742.78 |
1000/1000 ~ 200/200 | 2999.27 | 1436.24 | 1150.21 | 935.22 |
4、結論
> Thread就像脫繮的野馬,不受控制,建立多少就運行多少,可能少許時效率是高了,量大的時候除了性能沒優點,還可能致使句柄泄露。
> ThreadPool與Task相似,但Task相比效率更高用法更靈活。
> Parallel自帶了同步功能,不須要用信號量來作額外的同步等待。
> ThreadPool、Task、Parallel的性能都取決於線程池最大線程數和最小線程數。
> 推薦使用 Task 和 Parallel,具體用哪一個能夠參考用法本身斟酌。