多線程之Parallel類

来源:http://www.cnblogs.com/afei-24/archive/2017/05/25/6904179.html
-Advertisement-
Play Games

Parallel類是對線程的一個抽象。該類位於System.Threading.Tasks名稱空間中,提供了數據和任務並行性。 Paraller類定義了數據並行地For和ForEach的靜態方法,以及任務並行的Invoke的靜態方法。Parallel.For()和Parallel.ForEach() ...


  Parallel類是對線程的一個抽象。該類位於System.Threading.Tasks名稱空間中,提供了數據和任務並行性。
  Paraller類定義了數據並行地For和ForEach的靜態方法,以及任務並行的Invoke的靜態方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中調用相同的代碼,Paraller.Invoke()允許調用不同的方法。

1.Parallel.For
  Parallel.For()方法類似C#語法的for迴圈語句,多次執行一個任務。但該方法並行運行迭代,迭代的順序沒有定義。
  Parallel.For()方法中,前兩個參數定義了迴圈的開頭和結束,第三個參數是一個Action委托。Parallel.For方法返回類型是ParallelLoopResult結構,它提供了迴圈是否結束的信息。
  Parallel.For有多個重載版本和多個泛型重載版本。
  示例:

     static void ForTest()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,i => {
                    Console.WriteLine("{0},task:{1},thread:{2}",i,Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(5000);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

        }

  輸出:
  

  任務不一定映射到一個線程上。線程也可以被不同的任務重用。


  上面的例子,使用了.NET 4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一個非同步(http://www.cnblogs.com/afei-24/p/6757361.html)方法,用於釋放線程供其它任務使用。
  示例:

  static void ForTestDelay()
        {
            ParallelLoopResult plr =
                Parallel.For(0, 10,async i => {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    await Task.Delay(1000);
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

            Console.ReadKey();

        }

  輸出:
  
  上面代碼使用了await關鍵字進行延遲,輸出結果顯示延遲前後的代碼運行在不同的線程中。而且延遲後的任務不再存在,只留下線程,這裡還重用了前面的線程。另一個重要的方面是,Parallel類的For方法並沒有等待延遲,而是直接完成。parallel類只等待它創建的任務,而不等待其它後臺活動。所以上面代碼使用了Console.ReadKey();使主線程一直運行,不然很可能看不到後面的輸出。

2.提前停止Parallel.For
  For()方法的一個重載版本接受第三個Action<int,ParallelLoopState>委托類型的參數。使用這個方法可以調用ParallelLoopState的Break()或Stop()方法,以停止迴圈。
  註意,前面說到,迭代的順序是沒有定義的。
  示例:

static void ForStop()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,(int i,ParallelLoopState pls)=> {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    if (i > 5)
                        pls.Break();
                });

            Console.WriteLine("is completed:{0}",plr.IsCompleted);
            Console.WriteLine("最低停止索引:{0}",plr.LowestBreakIteration);
        }

  輸出:
  
  迭代值在大於5時中斷,但其它已開始的任務同時執行。


3.對Parallel.For中的每個線程初始化
  Parallel.For方法使用多個線程來執行迴圈,如果需要對每個線程進行初始化,就可以使用Parallel.For<TLocal>()方法。除了from和to對應的值之外,Parallel.For方法的泛型版本還接受3個委托參數:
    第一個委托參數的類型是Func<TLocal>,這個方法僅對用於執行迭代的每個線程調用每一次。
    第二個委托參數為迴圈體定義了委托。該參數類型是Func<int, ParallelLoopState, TLocal, TLocal>。其中第一個參數是迴圈迭代,第二個參數ParallelLoopState允許停止迴圈,第三個參數接受從上面參數委托  Func<TLocal>返回的值,該委托還需返回一個TLocal類型的值。該方法對每次迭代調用。
    第三個委托參數指定一個委托Action<TLocal>,接受第二個委托參數的返回值。這個方法僅對用於執行迭代的每個線程調用每一次。

  示例:

      static void ForInit()
            {
                ParallelLoopResult plr =
                    Parallel.For(0,10,()=> {
                        Console.WriteLine("init thread:{0},task:{1}",Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return Thread.CurrentThread.ManagedThreadId.ToString();
                    },
                    (i, pls,strInit)=> {
                        Console.WriteLine("body:{0},strInit:{1},thraed:{2},task:{3}",i,strInit,Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return i.ToString();
                    },
                    (strI)=> {
                        Console.WriteLine("finally {0}",strI);
                    });
            }

  輸出:
  


4.Parallel.ForEach
  Parallel.ForEach方法遍歷實現了IEnumerable的集合,類似於foreach,但以非同步方式遍歷。沒有確定遍歷順序。

  示例:

    static void ForeachTest()
        {
            string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
            ParallelLoopResult plr =  Parallel.ForEach<string>(data, s =>
            {
                Console.WriteLine(s);
            });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");
        }

 

 

  如果需要中斷,可以使用ForEach的重載版本和參數ParallelLoopState。
  訪問索引器:

    ParallelLoopResult plr1 = Parallel.ForEach<string>(data, (s,pls,l) =>
            {
                Console.WriteLine("data:{0},index:{1}",s,l);
            });

 

5.Parallel.Invoke
  如果多個任務並行運行,可以使用Parallel.Invoke方法。該方法允許傳遞一個Action委托數組。

    static void ParallerInvoke()
        {
            Action[] funs = { Fun1,Fun2};

            Parallel.Invoke(funs);
        }

        static void Fun1()
        {
            Console.WriteLine("f1");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
        static void Fun2()
        {
            Console.WriteLine("f2");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }

 


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

-Advertisement-
Play Games
更多相關文章
  • 關於C 中的類型 在C 中類型分為值類型和引用類型,引用類型和值類型都繼承自System.Object類,幾乎所有的引用類型都直接從System.Object繼承,而值類型具體一點則繼承System.Object的子類,即繼承System.ValueType。而String類型卻有點特別,雖然它屬於 ...
  • 在日常開發中,我們會去捕捉很多的異常,來進行處理,通常我們的方法就是,在需要進行異常處理的地方加上 try catch 塊,但是,如果需要異常處理的地方很多,那麼,就會頻繁的去寫try catch 塊,對於我們天生‘懶惰’ 的程式員來說,總想找一個捷徑。於是,就會有全局異常處理,那麼,今天,我們就來 ...
  • 第一、簡單介紹 ManualResetEvent 允許線程通過發信號互相通信。通常,此通信涉及一個線程在其他線程進行之前必須完成的任務。當一個線程開始一個活動(此活動必須完成後,其他線程才能開始)時,它調用 Reset 以將 ManualResetEvent 置於非終止狀態,此線程可被視為控制 Ma ...
  • C#面向對象編程 什麼是面向對象? 面向對象編程是上個實際六十年代繼面向結構編程之後提出的一個新的編程思想 封裝,繼承,多態 封裝,繼承,多態是面向對象編程的核心: 封裝是實現面向對象程式設計的第一步,封裝就是將數據或函數等集合在一個個的單元中(我們稱之為類)。被封裝的對象通常被稱為抽象數據類型 意 ...
  • c#3種基本的條件判斷語句有1.if 2.if...else... 3.switch 1.5.1if結構 c#中if結構的語法與java完全相同,即 1. if(表達式) { 代碼塊 } 2. if...else...結構如下 if() { 代碼塊1 } else { 代碼塊2 } 3. 多重if結 ...
  • 微軟最近幾年在跨平臺上不斷發力,很多.net程式員也摩拳擦掌,對微軟寄以厚望。就在最近,微軟還推出了asp .net core2.0預覽版。 通過對.net core的簡單嘗試,我發現以往我們開發MVC項目時,是通過新建一個.edmx文件來生成和更新實體模型,但是在core中,微軟去掉了.edmx, ...
  • 問題描述 使用 Windows Server 2012 R2 或 Windows Server 2016系統,發現在安裝 .NET Framework 3.5.1 時報錯,報錯內容如下圖所示。 原因分析 找不到安裝源文件。 解決辦法 您可以使用如下 PowerShell 腳本進行安裝。 從 開始 菜 ...
  • 1、將解壓後的“KindEditor”文件夾複製到項目的根目錄(此KindEditor文件夾已經經過優化) 下載地址為: http://pan.baidu.com/s/1eS1PRii 2、在<head>標簽中引入KindEditor外部樣式表文件和必需的外部js文件。如下所示: <!--引入樣式表 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...