為什麼要學習多線程?
下面通過一些實例來認識一下多線程和讓大家知道為什麼要學習多線程。
老板只有兩種,好的和壞的。好的老板只跟你談錢,壞的老板只跟你談理想。
假設後台有個monitor時事的在監測訂單,且可以發現訂單然後處理訂單,每次(1次/S)可以處理1千個訂單,需要向倉庫系統發出指令,讓他們負責配送發貨。那麼我們來寫一個EmulationSystem(模擬系統)
JobHelper因為我們只是為了模擬一個環境,所以它是這樣的。
//------------------------------------------------------------------------------ // <copyright file="JobHelper.cs" company="CNBlogs Corporation" owner="請叫我頭頭哥"> // Copyright (C) 2015-2016 All Rights Reserved // 原博文地址: http://www.cnblogs.com/toutou/ // </copyright> //------------------------------------------------------------------------------ namespace CNBlogs.Common.Shared { using System.Threading; /// <summary> /// Job helper /// </summary> public class JobHelper { /// <summary> /// Get job total count /// </summary> /// <returns></returns> public int GetJobCount() { // 我們的側重點是多線程,所以我們就模擬每次有1千個訂單,而模擬,所以我們不關心其他的。只要訂單數量。 return 1000; } /// <summary> /// Submit job /// </summary> /// <param name="jobId">For job id</param> /// <returns>Submit job status</returns> public bool SubmitJob(int jobId) { // 假設針對每個訂單向後台發送任務需要1秒,而且每個訂單都能成功發送 Thread.Sleep(1000); return true; } } }
背景我們也交待完了,現在需要來得到這些訂單信息以後,向倉庫submit這些訂單。
根據這種背景,我們可以有很多處理的辦法。
(開啟無腦模式:未使用多線程)
代碼正文:
//------------------------------------------------------------------------------ // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="請叫我頭頭哥"> // Copyright (C) 2015-2016 All Rights Reserved // 原博文地址: http://www.cnblogs.com/toutou/ // </copyright> //------------------------------------------------------------------------------ namespace CNBlogs.EmulationSystem { using System; using System.Threading; using CNBlogs.Common.Shared; class Runner { /// <summary> /// Job helper /// </summary> private static JobHelper jobHelper = new JobHelper(); /// <summary> /// Runner lock /// </summary> private static Mutex mutex; static void Main(string[] args) { // 記錄開始處理的時間 DateTime paddingTime = DateTime.Now.ToLocalTime(); int orderCount = jobHelper.GetJobCount(); // 用一個指示調用線程是否應擁有互斥體的初始所屬權的布爾值來初始化 Mutex 類的新實例。 // 當前進程只能啟動一次 mutex = new Mutex(false, "CNBlogs.EmulationSystem"); if (!mutex.WaitOne(0, false)) { Console.Out.WriteLine("Monitor already running..."); return; } for (int i = 0; i < orderCount; i++) { // 假設i就是job id jobHelper.SubmitJob(i); } // 記錄處理完成的時間 DateTime completeTime = DateTime.Now.ToLocalTime(); var minutes = (completeTime - paddingTime).TotalSeconds; Console.WriteLine(string.Format("處理{0}個訂單,花費時間{1}秒", orderCount, minutes)); } } }
代碼效果:
PS:現在的這些個電商,動不動來個什麼周年慶店慶什麼雙11雙12的一頓突突,搞得咱這些老百姓就全部蜂擁而上,顯然如果用傳統的方法雖然不會出錯,但是老板肯定會找你喝茶。在多核時代用這種方法也只能恨鐵不成鋼了。所以這個方法是絕對不可取的。
如果有對Task不是很熟悉的園友可以在這裡解開心謎。
代碼正文:
//------------------------------------------------------------------------------ // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="請叫我頭頭哥"> // Copyright (C) 2015-2016 All Rights Reserved // 原博文地址: http://www.cnblogs.com/toutou/ // </copyright> //------------------------------------------------------------------------------ namespace CNBlogs.EmulationSystem { using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using CNBlogs.Common.Shared; class Runner { /// <summary> /// Job helper /// </summary> private static JobHelper jobHelper = new JobHelper(); /// <summary> /// Runner lock /// </summary> private static Mutex mutex; static void Main(string[] args) { // 記錄開始處理的時間 DateTime paddingTime = DateTime.Now.ToLocalTime(); int orderCount = jobHelper.GetJobCount(); // 用一個指示調用線程是否應擁有互斥體的初始所屬權的布爾值來初始化 Mutex 類的新實例。 // 當前進程只能啟動一次 mutex = new Mutex(false, "CNBlogs.EmulationSystem"); if (!mutex.WaitOne(0, false)) { Console.Out.WriteLine("Monitor already running..."); return; } var taskList = new List<Task>(); for (int i = 0; i < orderCount; i++) {
int temp=i; taskList.Add(Task.Factory.StartNew(() => { // 假設i就是job id jobHelper.SubmitJob(temp); })); } // 等待所有task執行完畢 Task.WaitAll(taskList.ToArray()); // 記錄處理完成的時間 DateTime completeTime = DateTime.Now.ToLocalTime(); var minutes = (completeTime - paddingTime).TotalSeconds; Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes)); } } }
代碼效果:
相信分別從有TASK和沒有TASK的這兩次demo中,可以清楚的發現多線程處理這些頻繁交互能力的魅力。你會愛上這個方法。確實提高的效率。但是問題也隨之而來,一個進程多線程的總數和大小是有要求的(這個取決於服務器的配置),不是任由我們肆意的開采的。如果訂單太多,我們不控制task那是會拉仇恨的。task需要控制。
如果有對Semaphore不是很熟悉的園友可以在這裡解開心謎。
代碼正文:
//------------------------------------------------------------------------------ // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="請叫我頭頭哥"> // Copyright (C) 2015-2016 All Rights Reserved // 原博文地址: http://www.cnblogs.com/toutou/ // </copyright> //------------------------------------------------------------------------------ namespace CNBlogs.EmulationSystem { using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using CNBlogs.Common.Shared; class Runner { /// <summary> /// Job helper /// </summary> private static JobHelper jobHelper = new JobHelper(); /// <summary> /// The locker used to lock the semaphore and thread. /// </summary> private static object lockerObj = new object(); /// <summary> /// The semaphore limit the thread number of get latest test info /// </summary> private static Semaphore semaphoreLimit; /// <summary> /// Runner lock /// </summary> private static Mutex mutex; static void Main(string[] args) { // 記錄開始處理的時間 DateTime paddingTime = DateTime.Now.ToLocalTime(); int orderCount = jobHelper.GetJobCount(); // 用一個指示調用線程是否應擁有互斥體的初始所屬權的布爾值來初始化 Mutex 類的新實例。 // 當前進程只能啟動一次 mutex = new Mutex(false, "CNBlogs.EmulationSystem"); if (!mutex.WaitOne(0, false)) { Console.Out.WriteLine("Monitor already running..."); return; } // 假設我們的服務器一個進程只能接受的大小=當前線程大小*500 ps:500是設置信號量的最大值 int maxProcNumber = 500; using (semaphoreLimit = new Semaphore(0, maxProcNumber)) { // 以指定的次數退出信號量並返回前一個計數。 semaphoreLimit.Release(maxProcNumber); var taskList = new List<Task>(); for (int i = 0; i < orderCount; i++) {
int temp=i; // 如果SubmitJob有IO或者其他容易因為沖突而引起異常的話,這裡需要加上lock //lock (lockerObj) //{ semaphoreLimit.WaitOne(); taskList.Add(Task.Factory.StartNew(() => { // 假設i就是job id jobHelper.SubmitJob(temp); // 退出信號量並返回前一個計數。 semaphoreLimit.Release(); })); //} } // 等待所有task執行完畢 Task.WaitAll(taskList.ToArray()); } // 記錄處理完成的時間 DateTime completeTime = DateTime.Now.ToLocalTime(); var minutes = (completeTime - paddingTime).TotalSeconds; Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes)); } } }
代碼效果:
多線程路還很長...
作 者:請叫我頭頭哥
出 處:http://www.cnblogs.com/toutou/
關於作者:專注於微軟平台的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!