場景
有一個這樣場景,程序會有一個非常耗時的操作,但要求耗時的操作完成後,再順序的執行一個不耗時的操作,而且這個程序的調用,可能存在同時調用的情況。
具體的模型如下:
從Start開始觸發了5個線程,經過一個longTimeJob同時執行,我們不關心longJob的執行時間和先後順序,根據Start的先後順序來執行一個ShortJob。下面我們用代碼來模擬上面的過程。
舉例說明:有ABCD 4個線程,進入的順序也是ABCD,A耗時3s,B耗時7s,C耗時1s,D耗時3s. 所以如果當4個線程都同時開始執行時,完成的先後順序爲 CADB,但我們要求的順序是ABCD,也就是說C要等待AB執行完後,才能繼續後續的工作。
我們可以用請求bing搜索來模擬longTimeJob,根據傳入的序列來決定請求多少次,主要模擬方法如下:
private static async Task Test() { var arry = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; var listTask = new List<Task<int>>(); foreach (var i in arry) { var i1 = i; var task = Task.Run(() => DoJob(i1)); listTask.Add(task); } foreach (var task in listTask) { Console.WriteLine("輸出-->:" + await task);// } } public static Task<int> DoJob(int o) { return Task.Run(() => { DoLongTimeThing(o); return o; }); } public static void DoLongTimeThing(int i) { Console.WriteLine("執行-->:" + i); for (int j = 0; j < i; j++) { HttpGet("http://cn.bing.com/"); } Console.WriteLine("執行完畢-->:" + i); } public static string HttpGet(string url) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); string content = reader.ReadToEnd(); return content; } catch (Exception e) { return e.Message; } }
執行結果:
上面的代碼大概能解決我們的問題,有一個問題,對於客戶的調用我們無法形成一個List,而且list是線程安全的,所以針對上述的方法在實際的業務場景中無法使用。
新思路
我們無法實現一個有序的Task列表,如果換一個角度考慮,當一個任務形成的時間,同時生成一個對應的HashCode,對HashCode進行一個隊列的入隊操作,當執行完成longTimeJob後,判斷是不是隊列的第一個Task的HashCode,如果是則執行,如果不是則繼續等待,切換線程。 具體如下思路如下圖:
public static Queue<string> Queue = new Queue<string>(); static void Main(string[] args) { var arry = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; foreach (var i in arry) { Console.WriteLine("進入Job順序-->:" + i); Test(i); } Console.ReadKey(); } public static void Test(int i) { var taskId = Guid.NewGuid().ToString(); Queue.Enqueue(taskId); Task.Factory.StartNew(DoJob, new object[] { i, taskId }); } public static void DoJob(object o) { var oArry = (object[])o; var n = (int)oArry[0]; var currId = oArry[1].ToString(); DoLongTimeThing(n);// while (currId != Queue.Peek()) { Thread.Sleep(1);//等線程切換 } Console.WriteLine("DoShortJob輸出-->:" + n);// //請求數據庫 Queue.Dequeue(); } public static void DoLongTimeThing(int i) { Console.WriteLine("LongTimeJob執行-->:" + i); for (int j = 0; j < i; j++) { HttpGet("http://cn.bing.com/"); } Console.WriteLine("LongTimeJob執行完畢-->:" + i); } public static string HttpGet(string url) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); string content = reader.ReadToEnd(); return content; } catch (Exception e) { return e.Message; } }
運行結果如下:
雖然執行結果看起來很亂,但仔細比對可以發現最終的DoShortTime是按順序執行的。
(本文完)
作者:老付 如果覺得對您有幫助,可以下方的訂閱,或者選擇右側捐贈作者,如果有問題,請在捐贈後諮詢,謝謝合作 如有任何知識產權、版權問題或理論錯誤,還請指正。 自由轉載-非商用-非衍生-保持署名,請遵循:創意共享3.0許可證 交流請加羣113249828:點擊加羣 或發我郵件 [email protected]