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

語言: CN / TW / HK

點選上方 藍字 進行關注

有小夥伴問我每天忽悠的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入門級教程,學習一個專題,瞭解特性/能力最重要, 剩下的就是結合場景去應用。

本文內容和製圖均為原創,文章永久更新地址請參閱左下角原文,如對您有所幫助,【在看、點贊】來一發,未嘗不可 。

往期 精彩 回顧

【推薦】.NET Core開發實戰影片課程   ★★★

.NET Core實戰專案之CMS 第一章 入門篇-開篇及總體規劃

【.NET Core微服務實戰-統一身份認證】開篇及目錄索引

Redis基本使用及百億資料量中的使用技巧分享(附影片地址及觀看指南)

.NET Core中的一個介面多種實現的依賴注入與動態選擇看這篇就夠了

10個小技巧助您寫出高效能的ASP.NET Core程式碼

用abp vNext快速開發Quartz.NET定時任務管理介面

在ASP.NET Core中建立基於Quartz.NET託管服務輕鬆實現作業排程

現身說法:實際業務出發分析百億資料量下的多表查詢優化

關於C#非同步程式設計你應該瞭解的幾點建議

C#非同步程式設計看這篇就夠了