共用方式為


平行演算法

平行模式程式庫 (PPL) 會提供對資料集合執行並行工作的演算法。 這些演算法與標準樣板程式庫 (STL) 所提供的演算法很相似。

平行演算法是由並行執行階段中的現有功能所組成。 例如,Concurrency::parallel_for 演算法會使用 Concurrency::structured_task_group 物件來執行平行迴圈反覆項目。 parallel_for 演算法會使用具有可用數目之運算資源的最佳方式來分割工作。

章節

本主題詳述下列平行演算法:

  • parallel_for 演算法

  • parallel_for_each 演算法

  • parallel_invoke 演算法

parallel_for 演算法

Concurrency::parallel_for 演算法會以平行方式重複執行相同的工作。 每個這些作業都是由反覆項目值參數化。 當您擁有無法在迴圈反覆項目之間共用資源的迴圈主體時,這個演算法就很有用。

parallel_for 演算法會以平行執行的最佳方式分割工作。 在工作負載不平衡時,它會使用工作竊取演算法來平衡這些分割。 當一個迴圈反覆項目以合作方式封鎖時,執行階段會將指派給目前執行緒的反覆項目範圍重新分配到其他執行緒或處理器。 同樣地,當一個執行緒完成某個反覆項目範圍時,執行階段也會將工作從其他執行緒重新分配到該執行緒。 parallel_for 演算法也支援「巢狀平行處理原則」(Nested Parallelism)。 當某個平行迴圈包含另一個平行迴圈時,執行階段會以對平行執行最有效率的方式,在迴圈主體之間協調處理資源。

parallel_for 演算法具有兩個多載版本。 第一個版本會接受起始值、結束值和工作函式 (Lambda 運算式、函式物件或函式指標)。 第二個版本會接受起始值、結束值、間距值和工作函式。 這個函式的第一個版本會使用 1 當做間距值。

您可以將許多 for 迴圈轉換成使用 parallel_for。 不過,parallel_for 演算法與 for 陳述式具有下列差異:

  • parallel_for 演算法 parallel_for 不會按照預先決定的順序執行工作。

  • parallel_for 演算法不支援任意終止條件。 當反覆運算變數目前的值比 _Last 少一時,parallel_for 演算法就會停止。

  • _Index_type 型別參數必須是整數類資料型別。 整數類資料型別可以是帶正負號或不帶正負號。

  • 迴圈反覆項目必須是順向。 如果 _Step 參數小於 1,parallel_for 演算法就會擲回 std::invalid_argument 型別的例外狀況。

  • parallel_for 演算法的例外處理機制不同於 for 迴圈的例外處理機制。 如果同時在平行迴圈主體中發生多個例外狀況,執行階段只會將其中一個例外狀況傳播至呼叫 parallel_for 的執行緒。 此外,當一個迴圈反覆項目擲回例外狀況時,執行階段不會立即停止整體迴圈, 而是讓迴圈處於取消狀態,而且執行階段會捨棄任何尚未啟動的工作。 如需例外處理和平行演算法的詳細資訊,請參閱並行執行階段的例外處理

雖然 parallel_for 演算法不支援任意終止條件,不過您可以使用取消來停止所有工作。 如需取消的詳細資訊,請參閱 PPL 中的取消

注意事項注意事項

負載平衡和取消等功能支援所產生的排程成本可能大於平行執行迴圈主體的好處,特別是在迴圈主體相當小時。

範例

下列範例會示範 parallel_for 演算法的基本結構。 這個範例會將 [1, 5] 範圍中的每個值平行列印至主控台。

// parallel-for-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <array>
#include <sstream>
#include <iostream>

using namespace Concurrency;
using namespace std;

int wmain()
{
   // Print each value from 1 to 5 in parallel.
   parallel_for(1, 6, [](int value) {
      wstringstream ss;
      ss << value << L' ';
      wcout << ss.str();
   });
}

這個範例 (Example) 會產生下列範例 (Sample) 輸出:

1 2 4 3 5

因為 parallel_for 演算法平行作用於每個項目,所以列印到主控台之值的順序可能會不同。

如需使用 parallel_for 演算法的完整範例,請參閱 HOW TO:撰寫 parallel_for 迴圈

回到頁首

parallel_for_each 演算法

Concurrency::parallel_for_each 演算法會以平行方式針對例如 STL 所提供的反覆容器執行工作。 它會使用 parallel_for 演算法所使用的相同分割邏輯。

parallel_for_each 演算法與 STL std::for_each 演算法很相似,不過 parallel_for_each 演算法會執行並行工作。 與其他平行演算法相同的是,parallel_for_each 不會按照特定順序執行工作。

雖然 parallel_for_each 演算法可同時處理順向 Iterator 和隨機存取 Iterator,不過隨機存取 Iterator 的執行效能比較好。

範例

下列範例會示範 parallel_for_each 演算法的基本結構。 這個範例會將 std::array 物件中的每個值平行列印至主控台。

// parallel-for-each-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <array>
#include <sstream>
#include <iostream>

using namespace Concurrency;
using namespace std;

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

   // Print each value in the array in parallel.
   parallel_for_each(values.begin(), values.end(), [](int value) {
      wstringstream ss;
      ss << value << L' ';
      wcout << ss.str();
   });
}

這個範例 (Example) 會產生下列範例 (Sample) 輸出:

4 5 1 2 3

因為 parallel_for_each 演算法平行作用於每個項目,所以列印到主控台之值的順序可能會不同。

如需使用 parallel_for_each 演算法的完整範例,請參閱 HOW TO:撰寫 parallel_for_each 迴圈

回到頁首

parallel_invoke 演算法

Concurrency::parallel_invoke 演算法會以平行方式執行一組工作。 它會等到每個工作都完成之後才傳回。 當您擁有許多想要同時執行的獨立工作時,這個演算法就很有用。

parallel_invoke 演算法會接受一連串工作函式 (Lambda 函式、函式物件或函式指標) 當做其參數。 parallel_invoke 演算法會進行多載,以便接受二到十個參數。 您傳遞給 parallel_invoke 的每個函式都必須接受零個參數。

與其他平行演算法相同的是,parallel_invoke 不會按照特定順序執行工作。 工作平行處理原則 (並行執行階段) 主題說明 parallel_invoke 演算法與工作和工作群組之間的關聯性。

範例

下列範例會示範 parallel_invoke 演算法的基本結構。 這個範例會在三個區域變數上呼叫 twice 函式,然後將結果列印到主控台。

// parallel-invoke-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <string>
#include <iostream>

using namespace Concurrency;
using namespace std;

// Returns the result of adding a value to itself.
template <typename T>
T twice(const T& t) {
   return t + t;
}

int wmain()
{
   // Define several values.
   int n = 54;
   double d = 5.6;
   wstring s = L"Hello";

   // Call the twice function on each value concurrently.
   parallel_invoke(
      [&n] { n = twice(n); },
      [&d] { d = twice(d); },
      [&s] { s = twice(s); }
   );

   // Print the values to the console.
   wcout << n << L' ' << d << L' ' << s << endl;
}

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

108 11.2 HelloHello

如需使用 parallel_invoke 演算法的完整範例,請參閱 HOW TO:使用 parallel_invoke 來撰寫平行排序常式HOW TO:使用 parallel_invoke 執行平行作業

回到頁首

相關主題

參考

parallel_for 函式

parallel_for_each 函式

parallel_invoke 函式