並行執行階段概觀

更新:2010 年 7 月

本文件提供並行執行階段的概觀。 它說明並行執行階段的優點、使用時機、其元件彼此互動和元件與作業系統和應用程式的互動。

章節

本文件包括下列章節:

  • 並行執行階段的重要性

  • 架構

  • C++ Lambda 運算式

  • 需求

並行執行階段的重要性

並行執行階段為同時執行的應用程式和應用程式元件提供了統一性和可預測性。 並行執行階段的其中兩個優點為「合作式工作排程」(Cooperative Task Scheduling) 和「合作式封鎖」(Cooperative Blocking)。

並行執行階段會使用合作式工作 (Task) 排程器,這個排程器實作工作竊取 (Work-Stealing) 演算法,將工作 (Work) 有效率地分配給運算資源。 例如,假設應用程式有兩個執行緒都是受相同的執行階段管理。 如果其中一個執行緒完成排定給它的工作 (Task),它就可以將另一個執行緒的工作 (Work) 攬到自己身上。 這項機制可以平衡應用程式的整體工作負載。

並行執行階段還提供同步處理基本型別,這些基本型別會使用合作式封鎖來同步處理資源存取。 例如,假設有項工作必須獨佔存取共用資源。 透過合作式封鎖,執行階段可以在第一個工作等候資源的同時,使用剩餘的配量來執行其他工作。 這個機制可提升運算資源最大使用率。

回到頁首

架構

並行執行階段分成四個元件:平行模式程式庫 (PPL)、非同步代理程式程式庫、工作排程器和資源管理員。 這些元件都位在作業系統與應用程式之間。 下圖顯示並行執行階段元件如何在作業系統與應用程式之間互動:

並行執行階段架構

並行執行階段架構

並行執行階段是高度「可組合」(Composable) 的,也就是說您可以合併現有功能,以完成更多工作。 並行執行階段會以低階元件組合出許多功能 (例如平行演算法)。

並行執行階段還提供同步處理基本型別,這些基本型別會使用合作式封鎖來同步處理資源存取。 如需這些同步處理基本型別的詳細資訊,請參閱同步處理資料結構

下列各節簡短概述每個元件所提供的功能和其使用時機。

平行模式程式庫

平行模式程式庫 (PPL) 提供一般用途的容器和演算法來執行細部平行處理原則。 PPL 透過提供平行演算法 (此演算法會將對資料集合或資料集的計算分散給各個運算資源),啟用「重要資料平行處理原則」(Imperative Data Parallelism)。 它也透過提供工作物件 (工作物件會將多個獨立作業分散給各運算資源),啟用「工作平行處理原則」(Task Parallelism)。

當本機計算可因平行執行方式而加快效能時,請使用平行模式程式庫。 例如,您可以使用 Concurrency::parallel_for 演算法,將現有的 for 迴圈轉換成以平行方式作業。

如需平行模式程式庫的詳細資訊,請參閱平行模式程式庫 (PPL)

非同步代理程式程式庫

非同步代理程式程式庫 (或簡稱「代理程式程式庫」(Agents Library)) 提供動作項目型程式設計模型和訊息傳遞介面,以進行粗略的資料流程和管線工作。 非同步代理程式可讓您在其他元件等候資料時執行工作,以有效運用延遲時間。

當您有多個實體會以非同步方式相互通訊時,請使用代理程式程式庫。 例如,您可以建立代理程式以從檔案或網路連接讀取資料,然後使用訊息傳遞介面將該資料傳送給另一個代理程式。

如需代理程式程式庫的詳細資訊,請參閱非同步代理程式程式庫

工作排程器

工作排程器可在執行階段排定和協調工作。 工作排程器是合作式的,並會使用工作竊取演算法達成處理資源最大使用率。

並行執行階段所提供的預設排程器,可讓您無須管理基礎結構細節。 但若要達到您對應用程式的品質要求,您也可以提供自己的排程原則,或建立特定排程器與特定工作的關聯。

如需工作排程器的詳細資訊,請參閱工作排程器 (並行執行階段)

資源管理員

資源管理員的角色是管理諸如處理器和記憶體這類的運算資源。 當工作負載在執行階段發生變更時,資源管理員會將資源指派至它們最能發揮效益的位置做為因應。

資源管理員是運算資源的抽象概念,主要是與工作排程器互動。 雖然您可以使用資源管理員來微調程式庫和應用程式的效能,但是您通常會使用平行模式程式庫、代理程式程式庫和工作排程器所提供的功能。 這些程式庫會使用資源管理員,在工作負載變更時動態地重新平衡資源。

回到頁首

C++ Lambda 運算式

並行執行階段所定義的許多型別和演算法都是以 C++ 範本的形式實作。 其中部分型別和演算法都會以實際執行工作的常式做為參數。 這個參數可以是 Lambda 函式、函式物件或函式指標。 這些實體也稱為「工作函式」(Work Function) 或「工作常式」(Work Routine)。

Lambda 運算式是重要的新 Visual C++ 語言功能,因為它為平行處理提供定義工作函式的簡潔語法。 每個函式物件和函式指標都可讓您將並行執行階段搭配現有程式碼使用。 不過,建議您在撰寫新程式碼時使用 Lambda 運算式,因為它提供了安全和產能優點。

下列範例在 Concurrency::parallel_for_each 演算法的多重呼叫中比較 Lambda 函式、函式物件和函式指標的語法。 每個 parallel_for_each 呼叫都會使用不同的技巧來計算 std::array 物件中每個項目的平方。

// comparing-work-functions.cpp
// compile with: /EHsc
#include <ppl.h>
#include <array>
#include <iostream>

using namespace Concurrency;
using namespace std;

// Function object (functor) class that computes the square of its input.
template<class Ty>
class SquareFunctor
{
public:
   void operator()(Ty& n) const
   {
      n *= n;
   }
};

// Function that computes the square of its input.
template<class Ty>
void square_function(Ty& n)
{
   n *= n;
}

int wmain()
{
   // Create an array object that contains 5 values.
   array<int, 5> values = { 1, 2, 3, 4, 5 };

   // Use a lambda function, a function object, and a function pointer to 
   // compute the square of each element of the array in parallel.

   // Use a lambda function to square each element.
   parallel_for_each(values.begin(), values.end(), [](int& n){n *= n;});

   // Use a function object (functor) to square each element.
   parallel_for_each(values.begin(), values.end(), SquareFunctor<int>());

   // Use a function pointer to square each element.
   parallel_for_each(values.begin(), values.end(), &square_function<int>);

   // Print each element of the array to the console.
   for_each(values.begin(), values.end(), [](int& n) { 
      wcout << n << endl;
   });
}

這個範例會產生下列輸出。

1
256
6561
65536
390625

如需 C++ 中 Lambda 函式的詳細資訊,請參閱 Lambda Expressions in C++

回到頁首

需求

下表顯示與並行執行階段的每個元件相關聯的標頭檔:

元件

標頭檔

平行模式程式庫 (PPL)

ppl.h

concurrent_queue.h

concurrent_vector.h

非同步代理程式程式庫

agents.h

工作排程器

concrt.h

資源管理員

concrtrm.h

並行執行階段是在 Concurrency 命名空間中宣告。 Concurrency::details 命名空間支援並行執行階段結構,並非設計要供您直接從程式碼中使用。

並行執行階段會做為 C 執行階段程式庫 (CRT) 的一部分提供。 如需如何建置使用 CRT 之應用程式的詳細資訊,請參閱 C Run-Time Libraries

回到頁首

變更記錄

日期

記錄

原因

2010 年 7 月

重新組織內容。

資訊加強。