hello task,咱們又見面啦!!前面已經通過三篇簡單的文章,對多執行緒的創建、運行、阻塞、等待、取消、延遲操作、異步方法等相關的知識點,通過這一些介紹,現在上手寫一個多執行緒就是分分鐘的小事件,如果需要看前三排文章的小伙伴,可以點擊下面鏈接快速閱讀謝謝!
說了那么多后,我仔細想了一下,還是要來點實際的專案用例比較實在,那么我現在就講我平時在專案中用常用的一些業務梳理處理,以供參考,寫到不好勿噴,有更好的解決方式,歡迎交流,謝謝!
應用一、多執行緒的中的取與舍
還是用上幾篇文章中的關于酒店客房的資料來為例分析,假設系統同時對接了x程、y龍、q哪三家介面資料,用戶進入到某一個酒店預訂頁面,系統需要實時的到第三方取該酒店對應房間的實時動態資料呈現給用戶,但是在這個程序中,不能讓用戶等待的太久,并且能夠盡可能多的提供多渠道給用戶選擇,那么這個時候該如何去實作這個需求呢?
做過聚合平臺的同學,無論是酒店、機票、咨詢等等,或多或少都會遇到這樣類似的業務場景,下面分享一下,我們平時是怎么實作,
簡單的說就是一個取與舍的邏輯,你想啊,不同的介面方,介面的查詢效率不盡相同,并且同一介面在不同時間處理時間也不盡相同,遇到某一些特殊情況,有可能一個介面資料需要等待5-10s甚至更久才能取出資料,這個時候你不可能讓用戶也等待這么久吧,如果是這樣,估計用戶早嚇跑了,況且這樣等待下去,也會對系統帶來很大的壓力,尤其是在做活動高峰期時,那直接就是系統的一個瓶頸了,
為了到達這一目的,那么在實作上,我們首先應該想到的是,在約定時間內未回傳資料的介面,那么我們直接放棄,只展示給用戶已取到的資料即可,那在技術上該如何實作呢?
在實作上,有了Task,一切都變得那么輕松啦,因為Task.Wait方法已經為我們考慮到了這樣的場景,直接使用即可,
我們看看Task.Wait的幾個重載吧:
看到了吧,在多載方法中,有一個timeOut欄位,該欄位就是用于舍棄超時未處理完成的執行緒任務,那具體該怎么用呢?直接上代碼吧!
static void Main(string[] args){ Console.WriteLine("開始獲取酒店資料......");// 獲取最新的客房資訊(假設最大等待時間為1S) List<string> listHotelRoomInfro = GetHotelRoomInfro(1000); Console.WriteLine("獲取酒店資料獲取完畢,獲取到的資料為:");foreach (var item in listHotelRoomInfro) { Console.WriteLine(item); } Console.ReadLine(); } /// <summary>/// 獲取最新的客房資訊/// </summary>/// <param name="maxWaitTimes">最大獲取時間(也就是舍棄時間),單位毫秒</param>/// <returns>客房資訊集合</returns>private static List<string> GetHotelRoomInfro(int maxWaitTimes) {// 模擬存盤獲取到的酒店客房資料集合 List<string> listHotelRoomInfro = new List<string>();// 在此我也分別對3種不同渠道,采用3種不同的方式來實作// 其一、通過傳統的 new 方式來實體化一個task物件,獲取 攜程 的客房資料 Task newCtripTask = new Task(() => {// 具體獲取業務邏輯處理... Thread.Sleep(new Random().Next(100, 999)); listHotelRoomInfro.Add("我是來自 攜程 的最新客房資訊"); });// 啟動 tsak newCtripTask.Start();// 其二、通過工廠 factory 來生成一個task物件,并自啟動:獲取 藝龍 的客房資料 Task factoryElongTask = Task.Factory.StartNew(() => {// 具體獲取業務邏輯處理... Thread.Sleep(new Random().Next(555, 1500)); listHotelRoomInfro.Add("我是來自 藝龍 的最新客房資訊"); });// 其三、通過 Task.Run(Action action) 來創建一個自啟動task:獲取 去哪兒網 的客房資料 Task runQunarTask = Task.Run(() => {// 具體獲取業務邏輯處理... Thread.Sleep(new Random().Next(1100, 2000)); listHotelRoomInfro.Add("我是來自 去哪兒網 的最新客房資訊"); });// 等待獲取介面,阻塞主流程,如果 在 指定的時間 maxWaitTimes未回傳資料的介面方直接舍棄掉 Task.WaitAll(new Task[] { newCtripTask, factoryElongTask, runQunarTask }, maxWaitTimes);return listHotelRoomInfro; }
運行結果:通過上面的運行結果,我們發現在1s內,只有攜程回傳了資料,那么最終也就只回傳給用戶攜程的資料,這個實體就這樣實作了,當然,wi相信你或許會有更好的實作,歡迎一起交流與學習,謝謝
應用二:動態創建多執行緒均批處理
?在實際專案中,我們會遇到需要根據待處理任務數量,動態創建多執行緒來最優化分批處理,哈哈哈是不是說的有點空洞,云里霧里的,不急不急,下面來一個實際場景,一看你就明明白白啦,
?需求:還是以酒店資料同步為例,具體需求是這樣的:
?1.手動批選擇指定酒店,單次最多可選擇500個
?2.系統需要以最快的方式同步會介面方的最新資料
?哈哈哈看了需求是不是覺得很簡單,就兩句話,那該如何來實作這個需求呢?
?也許你會說,簡單啊,根據所選擇的酒店以次排隊同步資料就對了嘛!這樣可不行哦,如果用戶選擇了500個酒店,假設每個酒店資料同步需要2秒,那么500條資料都需要1000秒,那需要接近20分鐘才處理完,這可不是時間最優啊!
?那你也要你還會說那就直接每一個酒店都開一個執行緒來處理,這樣速度是不是夠快啦!嗯你說的沒錯,這樣速度是上去了,但是呢,如果用戶選擇500個酒店,那么就需要創建500個執行緒,也就是500個并發,這樣會有什么問題呢?第一.你自己的服務器扛的住嗎?第二.如果你服務器扛的住,那么介面允許你這么干嘛?估計早都把你拉黑名單了,所以這也不是最優方案,
?哈哈,說了那么多,那么具體該如何來實作呢?其實也簡單,我想說的方案就去以上兩兩種方案的一個折中方案,動態的根據資源等多因素動態創建合理的執行緒,然后在并行處理,來來,直接上代碼!
class Program { /// <summary> /// 最多允許創建的執行緒數,可以通過組態檔來配置 /// 具體的值也該是由:服務器資源+介面限制等多因數來確定的 /// </summary> public static int maxThread = 10; static void Main(string[] args) { // 假設選擇處理20條酒店資料 List<string> listHotel = new List<string>(); for (int i = 0; i < 20; i++) { listHotel.Add($"我是酒店{(i + 1).ToString().PadLeft(2, '0')}"); } // 創建Tsak處理酒店資料同步 AsyncDynamicSynchronouslyHotel(listHotel); Console.ReadLine(); } /// <summary> /// 根據酒店資料量,動態創建Tsak來處理酒店資料同步 /// </summary> /// <param name="listHotel">待處理的酒店資料串列</param> private static void AsyncDynamicSynchronouslyHotel(List<string> listHotel) { object hotelTaskLock = new object(); // 先做一個非空判斷 if (listHotel == null || listHotel.Count < 1) { return; } // task執行緒陣列 List<Task> taskList = new List<Task>(); // 首先根據資源資料量+最大允許執行緒數來確定需要開啟的執行緒 int taskCount = listHotel.Count < maxThread ? listHotel.Count : maxThread; // 創建指定是task執行緒數 for (int i = 0; i < taskCount; i++) { // 創建一個task執行緒 taskList.Add(new Task(() => { while (listHotel != null && listHotel.Count > 0) { // 給該執行緒分配一個酒店處理任務 string hotelInfro = string.Empty; // 執行緒通過,加一個資源鎖 lock (hotelTaskLock) { // 在獲取到鎖后,還需要做一個資源判斷,避免獲取到鎖后,資源以及被消耗完畢 if (listHotel != null && listHotel.Count > 0) { hotelInfro = listHotel[0]; listHotel.Remove(hotelInfro); } } // 開始模擬真正的資料同步操作 if (!string.IsNullOrEmpty(hotelInfro)) { Thread.Sleep(1000); Console.WriteLine($"我是執行緒ID{Thread.CurrentThread.ManagedThreadId.ToString() },完成酒店【{hotelInfro}的資料同步處理"); } } })); // 啟動執行緒 taskList[i].Start(); } } }
運行結果:
設定最多開5個執行緒
設定對多開10個執行緒
?這樣就達到了自動的動態控制執行緒創建,當然這個里面還涉及到了執行緒同步等問題處理
總結:
?通過本篇文章,和大家分享了多執行緒的取與舍,多線的動態創建等等,在實際作業程序中,或多或多我們都會遇到這樣的場景,希望能夠有點幫助 ?
?好了,今天就說在這兒了,有什么問題,大家可以多多交流,最后祝大家元旦快樂
猜您喜歡:
第一篇:聊聊多執行緒哪一些事兒(task)之 一創建運行與阻塞
第二篇:聊聊多執行緒哪一些事兒(task)之 二 延續操作
第三篇:聊聊多執行緒那一些事兒(task)之 三 異步取消和異步方法
第四篇:聊聊多執行緒那一些事兒 之 四 經典應用(取與舍、動態創建)
END
為了更高的交流,歡迎大家關注我的公眾號,掃描下面二維碼即可關注,謝謝:

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/77443.html
標籤:.NET Core
上一篇:.NetCore3.0短網址專案
