三分鐘總覽微軟任務並行庫TPL


點擊上方藍字進行關注


有小夥伴問我每天忽悠的TPL是什麼?

☹️ 這次站位高一點,嚴肅講一講。

引言

俗話說,不想開飛機的程序員不是一名好爸爸;作爲微軟技術棧的老鳥,一直將代碼整潔之道奉爲經典, 優秀的程序員將優雅、高性能的代碼看成自己的臉面。

今天探討下我對.NET並行編程庫Task Parallel Library的理解,開足馬力,準備壓榨CPU了。

雙核cpu的真相.gif

技術背景

硬件線程和軟件線程

   多核處理器帶有一個以上的物理內核:物理內核是真正的獨立處理單元,多個物理內核使得多條指令能夠同時並行運行。

硬件線程也稱爲邏輯內核,一個物理內核可能會使用超線程技術提供多個硬件線程,所以一個硬件線程並不代表一個物理內核。程序通過Environment.ProcessorCount 得到的就是邏輯內核(本人的機器是i5-5300U 虛擬4核), Windows中每個運行的程序都是一個進程,每一個進程都會創建並運行一個或多個線程,這些線程稱爲軟件線程,硬件線程就像是一條泳道,而軟件線程就是在其中游泳的人。

並行場

.NET引入的Task Parallel Library(任務並行庫,TPL),動態地擴展併發度,以最有效的方式使用所有可用的處理器。

另外TPL支持分區工作、支持基於ThreadPool調度、支持取消異步操作、支持狀態管理。

通過TPL專注與讓程序完成你業務意義上的任務,同時最大限度的提高程序性能。

TPL同時支持數據並行、任務並行和流水線Dataflow

1.數據並行:有大量數據需要處理,並且必須對每一份數據執行同樣的操作;2.任務並行:通過任務併發運行不同的操作;3.流水線:任務並行和數據並行的結合體(需要引入System.Threading.Tasks.Dataflow組件庫) 
其中1、3 已經在上文演示,本文就隨手拿數據並行、任務並行聊一聊。

編程實踐

1. 數據並行

找到100000以內素數的個數

上文[共享內存併發模型],代碼可做如下優化:

由每個線程獨立計算線程內迭代產生的素數和,最後再對幾個和求和

using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;

/// <summary>
/// 利用並行編程庫Parallel,計算100000內素數的個數
/// </summary>
namespace Paralleler
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();
            ShareMemory();
            sw.Stop();
            Console.WriteLine($"優化後的共享內存併發模型耗時:{sw.Elapsed}");
        }

        static void ShareMemory()
        {
            var sum = 0;
            Parallel.For(1, 100000 + 1, () => 0, (x, state, local) =>
            {
                var f = true;
                if (x == 1)
                    f = false;
                for (int i = 2; i <= x / 2; i++)
                {
                    if (x % i == 0)  // 被[2,x/2]任一數字整除,就不是質數
                        f = false;
                }
                if (f == true)
                    local++;
                return local;
            },
                 local =>
                 {
                     Interlocked.Add(ref sum, local);
                 }
               );
            Console.WriteLine($"1-100000內質數的個數是{sum}");
        }
    }
}
參數1,2 表示數據並行要操作的對象;
參數3localInit表示某線程內迭代的初始值,將會作爲參數4body委託的第3個參數,只在線程第一次使用;

參數4body表示每個迭代都需要經歷的執行體, 這裏以線程爲單元處理迭代;


參數5
localFinally對每個線程的輸出再做一次計算,入參是參數4的輸出。

2. 任務並行

  讓許多方法並行運行的最簡單的方法就是使用Parallel類的Invoke方法,Invoke方法接受一個Action的參數組

void  System.Threading.Tasks.Parallel.Invoke(WatchMovie, HaveDinner, ReadBook, WriteBlog);

這段代碼會創建指向每一個方法的委託。

沒有特定的執行順序

Parallel.Invoke方法只有在4個方法全部完成之後纔會返回。它至少需要4個硬件線程才足以讓這4個方法併發運行。


但並不保證這4個方法能夠同時啓動運行,如果一個或者多個內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行。

捕捉並行循環中發生的異常

當並行迭代中調用的委託拋出異常,這個異常沒有在委託中被捕獲到時,就會變成一組異常,新的System.AggregateException負責處理這一組異常。

本文爲微軟TPL入門級教程,學習一個專題,瞭解特性/能力最重要, 剩下的就是結合場景去應用。

本文分享自微信公衆號 - 一線碼農聊技術(dotnetfly)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章