工作平行處理原則 (並行執行階段)
本文件說明並行執行階段中工作和工作群組的角色。「工作」(Task) 是執行特定工作的工作單位。工作通常可以和其他工作平行處理,也可以分解為,更精細,工作。「工作群組」(Task Group) 會組織工作集合。
請使用工作,在撰寫非同步程式碼並想要某項作業時,在非同步作業完成之後。例如,您可以使用工作非同步讀取檔案並繼續運作,本文件稍後說明,處理資料,才能使用之後。相反地,會使用解析平行工作的工作群組分割成較小的部分。例如,假設您有個將剩餘工作分成兩塊的遞迴演算法。您可以使用工作群組同時執行這些分割,然後等候個別工作完成。
![]() |
---|
當您想要以平行方式套用相同常式至集合的每個項目,請使用另一個平行演算法,例如 concurrency::parallel_for,而不是用戶端或工作群組。如需平行演算法的詳細資訊,請參閱平行演算法。 |
金鑰
當您以傳址方式將變數傳遞給 Lambda 運算式時,必須保證該變數的存留期會保存直到工作完成為止。
使用 工作concurrency::task (類別),當您撰寫非同步程式碼時。
使用工作群組 (例如 concurrency::task_group 類別或 concurrency::parallel_invoke 演算法),當您需要平行工作分解成較小的部分然後等候這些較小的部分完成時。
concurrency::task::then 使用方法建立接續。繼續 執行非同步是在另一個工作之後完成的工作。您可以連接到任意數目的接續形成非同步工作鏈結。
工作式繼續進行執行一定會排程,在前項工作完成後,,即使前項工作已取消或擲回例外狀況。
使用 concurrency::when_all 建立完成的工作,在集合中的每個成員工作完成之後。使用 concurrency::when_any 建立完成的工作,在一組的成員工作完成之後。
工作和工作群組可以參與 PPL 取消機制。如需詳細資訊,請參閱PPL 中的取消。
若要了解執行階段會如何處理工作和工作群組所擲回的例外狀況,請參閱 並行執行階段的例外狀況處理。
在文件中。
使用 Lambda 運算式
工作類別
接續工作
以值為基礎的接續工作
組成的工作
when_all 函式
when_any 函式
延遲執行工作
工作群組
比較 task_group 與 structured_task_group
範例
健全的程式設計
使用 Lambda 運算式
Lambda 運算式是一種常見方式定義因為它們的簡潔語法,由工作和工作群組中執行的工作。這在使用它們的一些秘訣:
因為在背景工作執行緒通常在執行中,請注意物件存留期 (Lifetime),當您擷取在 Lambda 運算式中的變數。當您以傳值方式擷取的變數,該變數的複本在 Lambda 主體進行。當您以傳址方式擷取,複本不會進行任何變更。因此,請確定您是以傳址方式擷取的存留期中所有變數的壽命比長工作使用它。
一般而言,不要依該擷取的變數會配置在堆疊上。這也表示不應該會擷取在堆疊上配置物件的成員變數。
是明確地指示您在 Lambda 運算式中擷取可協助您識別的變數要由值擷取至以傳址方式。因此不建議在 Lambda 運算式中使用 [=] 或 [&] 選項。
一個常見的模式是在接續鏈結的工作指派給變數,然後,另一個工作會讀取該變數。因為每個接續工作會保留該變數,的不同的複本就無法使用值擷取。如果是堆疊配置的,變數,因為變數可能不再有效,就無法使用參考也會被擷取。
若要解決這個問題,請使用智慧型指標,例如 std::shared_ptr,包裝變數和傳遞智慧型指標值。如此一來,基礎物件可以指派給和讀取和壽命比使用其工作的長度。請使用這個技巧,即使變數是指標或參考計數的控制代碼 (^) 對應至 Windows 執行階段物件。這個基本範例:
// lambda-task-lifetime.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <string>
using namespace concurrency;
using namespace std;
task<wstring> write_to_string()
{
// Create a shared pointer to a string that is
// assigned to and read by multiple tasks.
// By using a shared pointer, the string outlives
// the tasks, which can run in the background after
// this function exits.
auto s = make_shared<wstring>(L"Value 1");
return create_task([s]
{
// Print the current value.
wcout << L"Current value: " << *s << endl;
// Assign to a new value.
*s = L"Value 2";
}).then([s]
{
// Print the current value.
wcout << L"Current value: " << *s << endl;
// Assign to a new value and return the string.
*s = L"Value 3";
return *s;
});
}
int wmain()
{
// Create a chain of tasks that work with a string.
auto t = write_to_string();
// Wait for the tasks to finish and print the result.
wcout << L"Final value: " << t.get() << endl;
}
/* Output:
Current value: Value 1
Current value: Value 2
Final value: Value 3
*/
如需 Lambda 運算式的詳細資訊,請參閱 在 C++ 中使用 lambda 運算式。
[最上面]
工作類別
您可以使用 concurrency::task 類別組成工作將一組相關的作業。這個構成模型是以 繼續支援的概念。如上,或是 前項工作完成之後,繼續讓程式碼執行。前項工作的結果傳遞做為輸入至一個或多個繼續工作。當一個前項工作完成時,等候事件的任何接續工作排定。每個接續工作收到前項工作的結果的複本。然後,這些接續工作也可以是其他接續的前項工作,藉此建立工作的鏈結。繼續可協助您建立與其間的特定工作相依性的任意長度的鏈結。此外,工作也可以加入、移除或,在工作開始或透過合作方式之前,在它執行時。如需這個新的取消模型的詳細資訊,請參閱 PPL 中的取消。
task 是樣板類別。型別參數 T 是由工作產生的結果型別。如果工作不會傳回值,這個型別可以是 void 。T 無法使用 const 修飾詞。
當您建立工作時,可以提供執行工作的工作函式主體。以 Lambda 函式、函式指標或函式物件的格式,將這個工作函式中。若要等候工作完成,而不用取得結果,請呼叫方法。 concurrency::task::waittask::wait 方法傳回描述的 concurrency::task_status 值工作是否完成或取消。若要取得工作的結果,請呼叫方法。 concurrency::task::get呼叫這個方法 task::wait 等候工作完成,因此會封鎖目前執行緒的執行,直到結果可供使用。
下列範例顯示如何建立工作,等待其結果並顯示其值。因為它們提供更簡潔的語法,在本文件中的範例會使用 Lambda 函式。不過,在中,當您使用工作時,您也可以使用函式指標或函式物件。
// basic-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Create a task.
task<int> t([]()
{
return 42;
});
// In this example, you don't necessarily need to call wait() because
// the call to get() also waits for the result.
t.wait();
// Print the result.
wcout << t.get() << endl;
}
/* Output:
42
*/
concurrency::create_task 函式可讓您使用 auto 關鍵字而非宣告型別。例如,請考慮建立並列印單位矩陣的下列程式碼:
// create-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <string>
#include <iostream>
#include <array>
using namespace concurrency;
using namespace std;
int wmain()
{
task<array<array<int, 10>, 10>> create_identity_matrix([]
{
array<array<int, 10>, 10> matrix;
int row = 0;
for_each(begin(matrix), end(matrix), [&row](array<int, 10>& matrixRow)
{
fill(begin(matrixRow), end(matrixRow), 0);
matrixRow[row] = 1;
row++;
});
return matrix;
});
auto print_matrix = create_identity_matrix.then([](array<array<int, 10>, 10> matrix)
{
for_each(begin(matrix), end(matrix), [](array<int, 10>& matrixRow)
{
wstring comma;
for_each(begin(matrixRow), end(matrixRow), [&comma](int n)
{
wcout << comma << n;
comma = L", ";
});
wcout << endl;
});
});
print_matrix.wait();
}
/* Output:
1, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 1, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 1, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 1, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 1, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 1, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 1, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 1, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 1
*/
您可以使用 create_task 函式建立對等作業。
auto create_identity_matrix = create_task([]
{
array<array<int, 10>, 10> matrix;
int row = 0;
for_each(begin(matrix), end(matrix), [&row](array<int, 10>& matrixRow)
{
fill(begin(matrixRow), end(matrixRow), 0);
matrixRow[row] = 1;
row++;
});
return matrix;
});
如果例外狀況在工作執行期間擲回例外狀況,執行階段封送處理在後續的呼叫上的例外狀況。 task::get 或 task::wait,或是以工作為基礎的接續。如需工作例外處理機制的詳細資訊,請參閱 並行執行階段的例外狀況處理。
對於使用 task, concurrency::task_completion_event的範例,請參閱 逐步解說:使用工作和 XML HTTP 要求 (IXHR2) 連線,取消。( task_completion_event 類別本文件稍後的中說明)。
![]() |
---|
若要了解是針對在 Windows 市集 應用程式的工作的詳細資訊,請參閱 Asynchronous programming in C++ 和 使用 C++ 為 Windows 市集應用程式建立非同步作業。 |
[最上面]
接續工作
在非同步程式設計中,一個非同步作業在完成時叫用第二個作業,並將資料傳遞給該作業,是很常見的情形。傳統上,使用回呼方法,這種方式。在並行執行階段, 接續工作提供相同的功能。接續工作 (也簡稱為「接續」) 是指在前項完成時,由另一項工作 (稱為「前項」(Antecedent)) 所叫用的非同步工作。使用繼續執行,您可以:
將資料從前項傳遞至接續。
指定接續叫用或未叫用正確的條件。
以合作方式取消接續、,以及在開始之前,或在它執行時。
提供如何排程接續的提示。(這 Windows 市集 只套用至應用程式。如需詳細資訊,請參閱 使用 C++ 為 Windows 市集應用程式建立非同步作業)。
從相同的前項叫用多個接續。
叫用 (Invoke) 繼續完成時,所有或任何多個前項。
每一個繫結繼續進行任何長度。
使用接續處理由前項擲回的例外狀況。
在第一個工作完成時,這些功能可讓您執行一或多項工作。例如,您可以建立壓縮檔案的接續,在第一個工作會從磁碟中刪除之後。
下列範例會修改先前已使用方法 concurrency::task::then 排程列印前項工作的值的接續時),則可使用時顯示。
// basic-continuation.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
auto t = create_task([]() -> int
{
return 42;
});
t.then([](int result)
{
wcout << result << endl;
}).wait();
// Alternatively, you can chain the tasks directly and
// eliminate the local variable.
/*create_task([]() -> int
{
return 42;
}).then([](int result)
{
wcout << result << endl;
}).wait();*/
}
/* Output:
42
*/
您可以繫結和巢狀工作加入至任何長度。工作也可以有多個接續。下列範例說明如何將上一個工作的值三次的基本接續鏈結。
// continuation-chain.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
auto t = create_task([]() -> int
{
return 0;
});
// Create a lambda that increments its input value.
auto increment = [](int n) { return n + 1; };
// Run a chain of continuations and print the result.
int result = t.then(increment).then(increment).then(increment).get();
wcout << result << endl;
}
/* Output:
3
*/
繼續也可以傳回另一個工作。如果未取消,則這個工作在之後繼續執行。這個技術稱為 非同步回溯。非同步回溯很有用,在您要在背景中執行額外的工作,,但不要讓目前工作封鎖目前的執行緒。(中通常 Windows 市集 應用程式,會繼續在 UI 執行緒上執行)。下列範例顯示三項工作。第一個工作會執行,在接續工作之前執行其他工作。
// async-unwrapping.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
auto t = create_task([]()
{
wcout << L"Task A" << endl;
// Create an inner task that runs before any continuation
// of the outer task.
return create_task([]()
{
wcout << L"Task B" << endl;
});
});
// Run and wait for a continuation of the outer task.
t.then([]()
{
wcout << L"Task C" << endl;
}).wait();
}
/* Output:
Task A
Task B
Task C
*/
![]() |
---|
當工作接續的傳回型別時 N巢狀工作,產生的工作有型別 N,不是 task<N>,並完成,而巢狀工作完成。換句話說,繼續回溯巢狀工作。 |
[最上面]
以值為基礎的接續工作
將傳回型別為 T的 task 物件,您可以提供型別 T 或 task<T> 的值給其接續工作。接受型別的 T 繼續稱為的數值 會繼續。數值的接續排定在前項工作完成,而不會發生錯誤時並不會移除。接受型別的 task<T> 繼續,其參數稱為 工作架構會繼續。工作式繼續進行執行一定會排程,在前項工作完成後,,即使前項工作已取消或擲回例外狀況。您可以呼叫 task::get 達到前項工作的結果。如果前項工作已取消, task::get 擲回 concurrency::task_canceled。如果前項工作擲回例外狀況, task::get 會重新擲回例外狀況。其前項取消工作時,工作式繼續未標記為已取消。
[最上面]
組成的工作
本節說明 concurrency::when_all 和 concurrency::when_any 函式,可協助您撰寫多工作實作常見的模式。
when_all 函式
when_all 函式會導致在完整的一組工作之後完成的工作。這個函式會傳回這個集合包含每個工作的結果 std::vector 物件。下列基本範例使用 when_all 建立代表其他三個工作完成的工作。
// join-tasks.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <array>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Start multiple tasks.
array<task<void>, 3> tasks =
{
create_task([] { wcout << L"Hello from taskA." << endl; }),
create_task([] { wcout << L"Hello from taskB." << endl; }),
create_task([] { wcout << L"Hello from taskC." << endl; })
};
auto joinTask = when_all(begin(tasks), end(tasks));
// Print a message from the joining thread.
wcout << L"Hello from the joining thread." << endl;
// Wait for the tasks to finish.
joinTask.wait();
}
/* Sample output:
Hello from the joining thread.
Hello from taskA.
Hello from taskC.
Hello from taskB.
*/
![]() |
---|
您傳遞給 when_all 的工作必須一致。換言之,它們都必須傳回相同的型別。 |
如下列範例所示,您也可以使用 && 語法會造成在完整的一組工作之後完成的工作。
auto t = t1 && t2; // same as when_all
在一組工作完成後,通常會與一起使用 when_all 繼續執行動作。中的每一個產生 int 結果的範例前述範例修改為三個列印工作的總和該。
// Start multiple tasks.
array<task<int>, 3> tasks =
{
create_task([]() -> int { return 88; }),
create_task([]() -> int { return 42; }),
create_task([]() -> int { return 99; })
};
auto joinTask = when_all(begin(tasks), end(tasks)).then([](vector<int> results)
{
wcout << L"The sum is "
<< accumulate(begin(results), end(results), 0)
<< L'.' << endl;
});
// Print a message from the joining thread.
wcout << L"Hello from the joining thread." << endl;
// Wait for the tasks to finish.
joinTask.wait();
/* Output:
Hello from the joining thread.
The sum is 229.
*/
在此範例中,您也可以指定 task<vector<int>> 產生以工作為基礎的接續。
![]() |
---|
如果在集合中的任何工作取消工作或擲回例外狀況, when_all 立即完成並不會等候剩餘工作完成。如果擲回例外狀況,執行階段會重新擲回例外狀況,當您呼叫 task::get 或 task::wait 在 when_all 傳回的 task 物件。如果有多個工作擲回例外狀況,執行階段會選擇其中一個。因此,如果有,就會擲回例外狀況,請確定您正在等候所有工作完成。 |
[最上面]
when_any 函式
when_any 函式中引發完成的工作,以在集合的第一個工作完成。這個函式會傳回這個集合包含已完成工作且該工作的結果的 std::pair 物件。
when_any 函式特別適用於下列情況:
重複這項作業。考慮可以在許多方面所執行的演算法或作業。您可以使用 when_any 選取函式先關閉再取消剩餘的作業。
交錯作業。您可以啟動所有必須完成和使用 when_any 函式處理結果的多重作業時,每個作業完成。在作業完成後,您可以啟動一個或多個其他工作。
將位元組資料流的作業。您可以使用 when_any 函式藉由限制並行作業數目是由上述案例。
過期的作業。您可以使用 when_any 函式選取一項或多項工作和在指定時間之後完成的工作之間。
使用 when_all,通常會使用具有執行的 when_any 動作的接續,當第一個的一組工作完成時。下列基本範例使用 when_any 建立完成的工作,並在第一個其他三個工作完成。
// select-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <array>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Start multiple tasks.
array<task<int>, 3> tasks = {
create_task([]() -> int { return 88; }),
create_task([]() -> int { return 42; }),
create_task([]() -> int { return 99; })
};
// Select the first to finish.
when_any(begin(tasks), end(tasks)).then([](pair<int, size_t> result)
{
wcout << "First task to finish returns "
<< result.first
<< L" and has index "
<< result.second
<< L'.' << endl;
}).wait();
}
/* Sample output:
First task to finish returns 42 and has index 1.
*/
在此範例中,您也可以指定 task<pair<int, size_t>> 產生以工作為基礎的接續。
![]() |
---|
使用 when_all,傳遞至 when_any 的工作都必須傳回相同的型別。 |
您也可以使用 || 語法會如下列範例所示,在一組的第一個工作完成之後,工作完成的工作。
auto t = t1 || t2; // same as when_any
[最上面]
延遲執行工作
延遲工作的執行,直到條件滿足有時候是必要的,或啟動工作以回應外部事件。例如,在非同步程式設計中,您可能必須啟動工作以回應 I/O 完成事件。
兩種方法可以完成這項工作會使用繼續或啟動工作並等待在事件中工作的工作函式內。但是,您不能使用這些技術的其中一種情況。例如,若要建立接續,您必須將前項工作。不過,因此,如果您沒有前項工作,您可以建立前項工作完成事件的 工作完成事件 和最新鏈結,並在可用時。此外,在中,因為等候的工作也會封鎖執行緒,您可以使用工作完成事件執行工作,當非同步作業完成時,因此無限制執行緒。
concurrency::task_completion_event 類別有助於簡化工作的這種方式撰寫。如 task 類別,型別參數 T 是由工作產生的結果型別。如果工作不會傳回值,這個型別可以是 void 。T 無法使用 const 修飾詞。通常, task_completion_event 物件提供給要通知它的執行緒或工作,其值可用時。同時,會將一或多個工作設定為該事件的接聽程式。當事件設定時,接聽程式配置完成,且其接續排定執行。
對於使用 task_completion_event 實作完成工作的範例,在延遲,請參閱 HOW TO:建立在延遲之後才會完成的工作之後。
[最上面]
工作群組
「工作群組」(Task Group) 會組織工作集合。工作群組會將工作推入至工作竊取佇列。排程器會將工作從這個佇列中移除,並使用可用的運算資源執行這些工作。將工作加入至工作群組之後,您可以等候所有工作完成或取消尚未開始的工作。
PPL 以 concurrency::task_group 和 concurrency::structured_task_group 類別表示工作群組和 concurrency::task_handle 類別表示這些群組中執行的工作。task_handle 類別會封裝執行工作的程式碼。以 Lambda 函式的形式,如 task 類別,工作函式之前,函式指標或函式物件。您通常不必直接使用 task_handle 物件,而是將工作函式傳遞給工作群組,而工作群組就會建立及管理 task_handle 物件。
PPL 將工作群組分為兩類:「非結構化工作群組」(Unstructured Task Group) 和「結構化工作群組」(Structured Task Group)。task_group PPL 以類別表示非結構化工作群組和 structured_task_group 類別表示結構化工作群組。
![]() |
---|
PPL 也定義 concurrency::parallel_invoke 演算法,使用 structured_task_group 類別以平行方式執行一組工作。因為 parallel_invoke 演算法的語法比較簡潔,建議您盡可能使用它,而不要使用 structured_task_group 類別。平行演算法主題將更詳細說明 parallel_invoke。 |
當您擁有數個要同時執行的獨立工作,而且必須等候所有工作完成才能繼續時,使用 parallel_invoke。這個技術通常稱為 分岔和聯結 平行處理原則。當您擁有數個要同時執行的獨立工作,但是要等候工作稍後完成時,使用 task_group。例如,您可以將工作加入至 task_group 物件,並在另一個函式中或從另一個執行緒等候這些工作完成。
工作群組支援取消的概念。取消可讓您對所有使用中工作表示您要取消整體作業。取消也可避免啟動尚未啟動的工作。如需取消的詳細資訊,請參閱 PPL 中的取消。
執行階段也提供例外處理模型,可讓您從工作擲回例外狀況,並在等候相關工作群組完成時處理該例外狀況。如需此例外狀況處理模型的詳細資訊,請參閱並行執行階段的例外狀況處理。
[最上面]
比較 task_group 與 structured_task_group
雖然我們建議您使用 task_group 或 parallel_invoke 而不是 structured_task_group 類別,具有,例如的情況下,您要使用 structured_task_group,當您撰寫可執行變數指派編號或提供取消要求支援的平行演算法時。本節說明 task_group 和 structured_task_group 類別之間的差異。
task_group 類別為安全執行緒。因此您可以將工作加入至 task_group 物件以及從多個執行緒等候或取消 task_group 物件。structured_task_group 物件的建構和解構必須在相同的語彙範圍中發生。此外,structured_task_group 物件的所有作業都必須在相同的執行緒上發生。此規則的例外是和方法。 concurrency::structured_task_group::is_cancelingconcurrency::structured_task_group::cancel子工作隨時都可以呼叫這些方法來取消父工作群組或是檢查是否已取消。
在呼叫 concurrency::task_group::wait 或 concurrency::task_group::run_and_wait 方法之後,還可以在 task_group 物件上執行其他工作。相反地,在您呼叫或方法 concurrency::structured_task_group::waitconcurrency::structured_task_group::run_and_wait 之後,無法在 structured_task_group 物件上執行其他工作。
因為 structured_task_group 類別不會跨執行緒進行同步處理,所以它的執行額外負荷比 task_group 類別更少。因此,如果您的問題並不需要排定來自多個執行緒的工作,而且您無法撰寫 parallel_invoke 演算法,structured_task_group 類別有助於您撰寫執行效果更好的程式碼。
如果您在 structured_task_group 物件內部使用另一個 structured_task_group 物件,內部物件完成且終結之後,外部物件才能完成。task_group 類別不需要巢狀工作群組先完成然後再完成外部群組。
非結構化工作群組和結構化工作群組使用工作控制代碼的方式並不相同。您可以將工作函式直接傳遞給 task_group 物件,task_group 物件就會為您建立及管理工作控制代碼。structured_task_group 類別需要您為每個工作管理 task_handle 物件。每個 task_handle 物件在其相關 structured_task_group 物件的整個存留期都必須維持有效。如下列基本範例所示,使用 concurrency::make_task 函式會建立物件, task_handle :
// make-task-structure.cpp
// compile with: /EHsc
#include <ppl.h>
using namespace concurrency;
int wmain()
{
// Use the make_task function to define several tasks.
auto task1 = make_task([] { /*TODO: Define the task body.*/ });
auto task2 = make_task([] { /*TODO: Define the task body.*/ });
auto task3 = make_task([] { /*TODO: Define the task body.*/ });
// Create a structured task group and run the tasks concurrently.
structured_task_group tasks;
tasks.run(task1);
tasks.run(task2);
tasks.run_and_wait(task3);
}
若要在擁有可變數目的工作時管理工作控制代碼,請使用堆疊配置常式 (例如 _malloca) 或容器類別 (例如 std::vector)。
task_group 和 structured_task_group 都支援取消。如需取消的詳細資訊,請參閱 PPL 中的取消。
[最上面]
範例
下列基本範例顯示如何使用工作群組。這個範例會使用 parallel_invoke 演算法,同時執行兩個工作。每個工作都會將子任務加入至 task_group 物件。請注意,task_group 類別允許同時加入多個工作。
// using-task-groups.cpp
// compile with: /EHsc
#include <ppl.h>
#include <sstream>
#include <iostream>
using namespace concurrency;
using namespace std;
// Prints a message to the console.
template<typename T>
void print_message(T t)
{
wstringstream ss;
ss << L"Message from task: " << t << endl;
wcout << ss.str();
}
int wmain()
{
// A task_group object that can be used from multiple threads.
task_group tasks;
// Concurrently add several tasks to the task_group object.
parallel_invoke(
[&] {
// Add a few tasks to the task_group object.
tasks.run([] { print_message(L"Hello"); });
tasks.run([] { print_message(42); });
},
[&] {
// Add one additional task to the task_group object.
tasks.run([] { print_message(3.14); });
}
);
// Wait for all tasks to finish.
tasks.wait();
}
下列是這個範例 (Example) 的範例 (Sample) 輸出:
Message from task: Hello
Message from task: 3.14
Message from task: 42
因為 parallel_invoke 演算法會並行執行工作,所以輸出訊息的順序可能會不同。
如需示範如何使用 parallel_invoke 演算法的完整範例,請參閱 HOW TO:使用 parallel_invoke 來撰寫平行排序常式和 HOW TO:使用 parallel_invoke 執行平行作業。如需使用 task_group 類別來實作非同步未來的完整範例,請參閱逐步解說:實作未來。
[最上面]
健全的程式設計
請確定您了解取消和例外狀況處理的角色,當您使用工作、工作群組和平行演算法。例如,在平行工作的樹狀結構中,已取消的工作會導致子工作無法執行。如果其中一個子工作所執行的作業對應用程式很重要,例如釋放資源,這可能會造成問題。此外,如果子工作擲回例外狀況,該例外狀況可能會透過物件解構函式傳播,而在應用程式中造成未定義的行為。如需說明這些重點的範例,請參閱<平行模式程式庫中的最佳作法>文件的Understand how Cancellation and Exception Handling Affect Object Destruction一節。如需 PPL 中取消和例外狀況處理模型的詳細資訊,請參閱 PPL 中的取消和並行執行階段的例外狀況處理。
[最上面]
相關主題
標題 |
描述 |
---|---|
顯示如何使用 parallel_invoke 演算法改善雙調排序演算法的效能。 |
|
顯示如何使用 parallel_invoke 演算法,改善對共用資料來源執行多個作業的程式效能。 |
|
顯示如何使用 task、 cancellation_token_source、 cancellation_token和 task_completion_event 類別建立延遲之後完成的工作。 |
|
顯示如何將並行執行階段中的現有功能合併成可完成更多工作的單一項目。 |
|
說明 PPL,PPL 提供開發並行應用程式時的重要程式設計模型。 |