聊聊多線程那一些事兒 之 四 經典應用(取與舍、動態創建)

来源:https://www.cnblogs.com/xiaoXuZhi/archive/2019/12/31/XYH_Task_o4.html
-Advertisement-
Play Games

瞭解了多線程的基本使用後,現在我們來聊聊多線的實際項目場景:多線程的取與舍,也就是取在指定時間有響應結果的任務,捨棄未響應的任務。我們也遇到根據實際需要處理的業務量動態創建線程並控制等場景。 ...


   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
為了更高的交流,歡迎大家關註我的公眾號,掃描下麵二維碼即可關註,謝謝:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 Python 3.9 都已經進入 dev 版本的 2020 年,Python 2 終於要和我們告別了。 ...
  • 1.繼承Thread類 public class ThreadCreator extends Thread{ public static void main(String[] args) { //第一種方式: ThreadCreator creator = new ThreadCreator(); ...
  • 1.背景 1.當我的手機連接電腦的時候想要調試居然連接不上,之後我將項目發佈之後才可以請求(同一區域網下) 2.你們不覺得發佈到IIS再附加進程太煩了麽?看了看網上全是這種方法,這不科學!VS已經提供了更好的方式了。 2.準備 1.電腦和手機在同一個網路下麵。(外網請求,可以看我其他的博客了) 3. ...
  • XAML(Extensible Application Markup Language的簡寫,發音為“zammel”)是用於實例化.NET對象的標記語言。儘管XAML是一種應用於諸多不同問題領域的技術,但其主要作用是構造WPF用戶界面。換言之,XAML文檔定義了在WPF應用程式中組成視窗的面板、按鈕 ...
  • Lucene.net Lucene.net是Lucene的.net移植版本,是一個開源的全文檢索引擎開發包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,是一個高性能、可伸縮的文本搜索引擎庫。它的功能就是負責將文本數據按照某種分詞演算法進行切詞,分詞後的結 ...
  • 在平時開發過程中,數組是我們使用頻率最高的類型之一,在使用定長列表時,數組可以說是最佳方案,這也是我們最熟悉的數據結構之一。 在C#中使用數組,可以獲取在記憶體上連續的相同類型的一組變數,在連續訪問時可以滿足CPU訪問寄存器的時間局部性和空間局部性,大大提高了對大量數據的訪問效率,但是在使用它時我們依 ...
  • 微信公眾號:Dotnet9,網站:Dotnet9。問題或建議,請網站留言; 如果您覺得Dotnet9對您有幫助,歡迎贊賞 C WPF發票列印 內容目錄 1. 實現效果 2. 業務場景 3. 編碼實現 4. 本文參考 5. 源碼下載 1.實現效果 發票界面 PDF列印結果 2.業務場景 界面作為發票預 ...
  • 本筆記摘抄自:https://www.cnblogs.com/maitian-lf/p/3670570.html,記錄一下學習過程以備後續查用。 序列化是把一個記憶體中的對象的信息轉化成一個可以持久化保存的形式,以便於保存或傳輸。序列化的主要作用是不同平臺之間進行通信,常用的序 列化有json、xml ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...