ハンズオン ラボ
Parallel Extensions ラブラリの概要
ラボ バージョン: 1.0.0
目次 概要 ... 3 演習 1: 静的 PARALLEL ヘルパー クラスを使用した既存のアルゴリズムの並列化 ... 6 タスク 1 – 実行時間の長いサービスを並列化する ... 6 演習 2: 並列タスクの作成と実行 ... 23 タスク 1 – 並列タスクを特別な設定なしに実行する ... 23 タスク 2 – Wait() メソッドと WaitAll() メソッドを使用する ... 25 タスク 3 – IsCompleted プロパテゖを使用する ... 29 タスク 4 – ContinueWith() メソッドを使用する ... 31 演習 3: TASK<T> クラスを使用した値を返すタスクの作成と実行 ... 33 タスク 1 – タスクの戻り値を取得する ... 33 演習 4: PLINQ を使用した LINQ クエリの並列化 ... 35 タスク 1 – ParallelEnumerable クラスの静的メソッドを使用して LINQ を並列化する ... 36 タスク 2 – ParallelEnumerable クラスの拡張メソッドを使用して LINQ を並列化する ... 40 タスク 3 – AsParallel() をクエリの包含構文と併用する ... 44 まとめ ... 46
概要
最近のコンピューターでは、そのコンピューター上で実行するシステムが使用できるプロセ ッサ数やコゕ数が飛躍的に増加しました。システム開発者は、開発中のソフトウェゕにこう したメリットをさまざまな方法で取り入れることができます。特に、複雑なゕルゴリズムや 大規模なデータ セットを処理する際に役立ちます。
マクロソフトの Parallel Computing Platform (PCP: パラレル コンピューテゖング プラットフ ォーム) には、開発者が効率的で管理しやすく、スケーラブルな方法でこのメリットを活用 できるツールが用意されています。Parallel Extensions to .NET Framework により、こうしたツ ールセットにいくつもの重要な概念がもたらされます。たとえば、Task Parallel Library (TPL) や並列 LINQ (PLINQ) による命令型のタスク並列処理を使用すると、開発者はデータの並列処 理を宣言的な方法で扱うことができます。
目的
このハンズオン ラボでは、次のことを行う方法について学習します。 静的 Parallel ヘルパー クラスを使用して既存のゕルゴリズムを並列化し、自動的に 処理される同時実行を表現する。 実行中のタスクをキャンセルするといった機能を可能にするタスクを作成および実 行する。 Task<T> クラスを使用して、値を返すタスクを作成および実行する。 並列 LINQ (PLINQ) を使用して、LINQ クエリを並列環境での実行向けに最適化する。
システム要件
このラボには、次のものが必要です。 Microsoft Visual Studio 2010 Beta 2 .NET Framework 4
セットアップ
メモ: 日本語環境でこのラボを実行する場合は下記の Read Me を参考にして、セットゕッ プを実行してください。 http://msdn.microsoft.com/ja-jp/netframework/ff384798.aspx 構成ウゖザード (Configuration Wizard) を使用すると、このラボの要件がすべて確認されます。 すべての要件が正しく構成されていることを確認するには、次の手順を実行します。 メモ: セットゕップ手順を実行するには、管理者特権を使ってコマンド ウゖンドウからス クリプトを実行する必要があります。 1. トレーニング キットの構成ウゖザードを以前に実行していなければ、実行します。 これには、%TrainingKitInstallationFolder%\Labs\ParallelExtensions\Source\Setup フォ ルダーの CheckDependencies.cmd スクリプトを実行します。前提条件を満たしてい なければ、必要な項目をすべてンストールし (必要に応じて再スキャンし)、ウゖ ザードを完了します。 メモ: 便宜上、このラボで管理するコードの大半は、Visual Studio のコード スニペ ットとして使用できるようにしています。CheckDependencies.cmd フゔルによっ て Visual Studio ンストーラー フゔルが起動し、コード スニペットがンスト ールされます。 複数のバージョンの Visual Studio がンストールされている場合、対象のコード ス ニペットをすべて選択した上で、ンストール先に Visual Studio のバージョンを選 択してください。演習
このハンズオン ラボは、以下の演習から構成されています。 静的 Parallel ヘルパー クラスを使用した既存のゕルゴリズムの並列化 並列タスクの作成と実行 Task<T> クラスを使用した値を返すタスクの作成と実行 PLINQ を使用した LINQ クエリの並列化 ラボの推定所要時間: 60 分
次の手順:
演習 1: 静的 Parallel ヘルパー クラスを使用した既存のゕルゴリズムの並列化演習 1: 静的 Parallel ヘルパー クラスを
使用した既存のゕルゴリズムの並列化
この演習では、静的 Parallel ヘルパー クラスを使用して、既存のゕルゴリズムを並列化する 方法について学習します。たとえば、for() の代わりに Parallel.For() を使用できます。 メモ: 各手順を正しく実行していることを確認するために、各タスクの最後にソリューシ ョンをビルドすることをお勧めします。 タスク 1 – 実行時間の長いサービスを並列化する このタスクでは、簡単なサンプル コードを作成して、実行時間の長いサービス呼び出しの シミュレーションを行いますす。 ここでは、この演習の開始ソリューションとして用意されている PayrollServices.GetPayrollDeduction() メソッドを使用します。最終的に並列実行の対象とな るのは、この種の実行時間の長いコードです。1. Microsoft Visual Studio 2010 を起動します。[スタート] ボタンをクリックし、[すべて のプログラム]、[Microsoft Visual Studio 2010]、[Microsoft Visual Studio 2010] の順にク リックします。 2. %TrainingKitInstallationFolder%\Labs\IntroToParallelExtensions\Source\Ex01-UsingStaticParallelHelper\begin フォルダーの C# フォルダーもしくは VB フォルダーに ある ParallelExtLab.sln ソリューション フゔルを開きます。(お好きな言語を選択し てください。) メモ: このソリューションが作業の出発点となり、操作するデータを保持する EmployeeList ヘルパー クラスを含んでいます。
3. Visual Studio で、Program.cs フゔル (C#) または Module1.vb (Visual Basic) を開き
Main() メソッドに移動します。まず、操作対象の従業員一覧を作成する必要がある
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Create employee list CSharp) C#
class Program {
private static EmployeeList employeeData;
static void Main(string[] args) {
employeeData = new EmployeeList();
Console.WriteLine("Payroll process started at {0}", DateTime.Now); var sw = Stopwatch.StartNew();
// 呼び出すメソッド
Console.WriteLine("Payroll finished at {0} and took {1}", DateTime.Now, sw.Elapsed.TotalSeconds); Console.WriteLine();
Console.ReadLine(); }
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Create employee list VB) Visual Basic
Module Module1
Private employeeData As EmployeeList Sub Main(ByVal args() As String) employeeData = New EmployeeList()
Console.WriteLine("Payroll process started at {0}", DateTime.Now) Dim sw = Stopwatch.StartNew()
' Methods to call
Console.WriteLine("Payroll finished at {0} and took {1}", DateTime.Now, sw.Elapsed.TotalSeconds)
Console.WriteLine() Console.ReadLine() End Sub
EndModule
4. 次のメソッドを Program.cs (C#) または Module1.vb (Visual Basic)に追加します。この メソッドは、標準の for ループを使用して Employees の一覧を反復処理し、用意し たビルド済みのコードと同様、実行時間の長い PayrollServices.GetPayrollDeduction() メソッドを呼び出します。コードは次のようになります。
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 Ex1Task1_ParallelizeLongRunningService CSharp)
C#
private static void Ex1Task1_ParallelizeLongRunningService() {
Console.WriteLine("Non-parallelized for loop"); for (int i = 0; i < employeeData.Count; i++) {
Console.WriteLine("Starting process for employee id {0}", employeeData[i].EmployeeID);
decimal span =
PayrollServices.GetPayrollDeduction(employeeData[i]);
Console.WriteLine("Completed process for employee id {0}" + "process took {1} seconds",
employeeData[i].EmployeeID, span); Console.WriteLine();
} }
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Ex1Task1_ParallelizeLongRunningService VB)
Visual Basic
Private Sub Ex1Task1_ParallelizeLongRunningService() Console.WriteLine("Non-parallelized for loop") For i = 0 To employeeData.Count - 1
Console.WriteLine("Starting process for employee id {0}", employeeData(i).EmployeeID) Dim span As Decimal = PayrollServices.GetPayrollDeduction(employeeData(i))
Console.WriteLine("Completed process for employee id {0}" & "process took {1} seconds", employeeData(i).EmployeeID, span) Console.WriteLine() Next i End Sub 5. Main() メソッドから Ex1Task1_ParallelizeLongRunningService メソッドを呼び出します 。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex1Task1_ParallelizeLongRunningService(); ... }
Visual Basic
Sub Main(ByVal args() AsString) ... ' Methods to call Ex1Task1_ParallelizeLongRunningService() ... EndSub 6. ゕプリケーションをビルドして実行します。 7. 次の画面のように、すべての従業員が ID 順に処理されます (完了までの実際の時間 は状況によって異なります)。 図 1 実行時間の長いサービスを並列呼び出ししない場合の出力
8. 並列機能を使用するには、次のメソッドを Program.cs (C#) または Module1.vb (VB) に 追加します。このコードでは、静的 Parallel オブジェクトの For() メソッドを使用し ます。
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 Ex1Task1_UseParallelForMethod CSharp)
C#
private static void Ex1Task1_UseParallelForMethod() {
Parallel.For(0, employeeData.Count, i => {
Console.WriteLine("Starting process for employee id {0}", employeeData[i].EmployeeID);
decimal span =
PayrollServices.GetPayrollDeduction(employeeData[i]); Console.WriteLine("Completed process for employee id {0}", employeeData[i].EmployeeID);
Console.WriteLine(); });
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Ex1Task1_UseParallelForMethod VB)
Visual Basic
Private Sub Ex1Task1_UseParallelForMethod() Parallel.For(0, employeeData.Count, Sub(i)
Console.WriteLine("Starting process for employee id {0}", employeeData(i).EmployeeID) Dim span As Decimal = PayrollServices.GetPayrollDeduction(employeeData(i))
Console.WriteLine("Completed process for employee id {0}", employeeData(i).EmployeeID) Console.WriteLine() End Sub) End Sub 9. Main() メソッドから現在呼び出しているメソッドを、 Ex1Task1_UseParallelForMethod() メソッドに置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex1Task1_UseParallelForMethod(); ... }
Visual Basic
Sub Main(ByVal args() AsString) ... ' Methods to call Ex1Task1_UseParallelForMethod() ... EndSub 10. ゕプリケーションをビルドして実行します。 11. 今度は、従業員が必ずしも ID 順に処理されていません。また、最初の呼び出しから 戻る前に、GetPayrollDeduction() メソッドが複数呼び出されています。呼び出しを並 列実行すると、順次実行よりもジョブ全体が短時間で完了します。
図 2
メモ: ループが並列実行されるため、各反復処理のスケジュールが設定され、使用
可能なすべてのコゕで個別に実行されます。つまり、一覧が順序どおりに処理され るとは限らないため、コードに大きな影響を与えることがあります。ループ内の各 反復処理が互いに完全に独立するように、コードを設計してください。正常に処理 が完了するよう、どの反復処理も別の反復処理に依存しないようにします。
12. Parallel Extensions ラブラリには、並列バージョンの foreach 構造も用意されていま す。次のコードは、この構造の並列ではない実装方法を示しています。Program.cs (C#) または Module1.vb (Visual Basic) に次のメソッドを追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 Ex1Task1_StandardForEach Csharp)
C#
private static void Ex1Task1_StandardForEach() {
foreach (Employee employee in employeeData) {
Console.WriteLine("Starting process for employee id {0}", employee.EmployeeID);
decimal span =
PayrollServices.GetPayrollDeduction(employee);
Console.WriteLine("Completed process for employee id {0}", employee.EmployeeID);
Console.WriteLine(); }
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Ex1Task1_StandardForEach VB) Visual Basic
Private Sub Ex1Task1_StandardForEach()
For Each employee As Employee In employeeData
Console.WriteLine("Starting process for employee id {0}", employee.EmployeeID) Dim span As Decimal = PayrollServices.GetPayrollDeduction(employee)
Console.WriteLine("Completed process for employee id {0}", employee.EmployeeID) Console.WriteLine()
Next employee End Sub
C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex1Task1_StandardForEach(); ... } Visual Basic
Sub Main(ByVal args() AsString) ... ' Methods to call Ex1Task1_StandardForEach() ... EndSub 14. ゕプリケーションをビルドして実行します。 メモ: 従業員は再び ID 順に処理されます。このジョブの完了に要した合計時間にも 注目してください (実際の時間は状況によって異なります)。
図 3
並列処理しない for ... each 実装の出力
15. Parallel Extensions の for ... each 構造の実装を活用するために、Parallel クラスの
ForEach() メソッドを使用するようにコードを変更します。Program.cs (C#) または Module1.vb (Visual Basic) に次のメソッドを追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 Ex1Task1_ParallelForEach) C#
private static void Ex1Task1_ParallelForEach() {
Parallel.ForEach(employeeData, ed => {
Console.WriteLine("Starting process for employee id {0}", ed.EmployeeID);
decimal span = PayrollServices.GetPayrollDeduction(ed); Console.WriteLine("Completed process for employee id {0}", ed.EmployeeID);
Console.WriteLine(); });
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Ex1Task1_ParallelForEach VB) Visual Basic
Private Sub Ex1Task1_ParallelForEach() Parallel.ForEach(employeeData, Sub(ed)
Console.WriteLine("Starting process for employee id {0}", ed.EmployeeID) Dim span As Decimal = PayrollServices.GetPayrollDeduction(ed)
Console.WriteLine("Completed process for employee id {0}", ed.EmployeeID) Console.WriteLine() End Sub) End Sub 16. Main() メソッドから現在呼び出しているメソッドを、Ex1Task1_ParallelForEach メソ ッドに置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex1Task1_ParallelForEach(); ... } Visual Basic
Sub Main(ByVal args() AsString) ... ' Methods to call Ex1Task1_ParallelForEach() ... EndSub 17. ゕプリケーションをビルドして実行します。
18. また、従業員が ID 順に処理されなくなります。各ループが並列実行されるため、ル ープ内の各反復処理が使用可能なすべてのコゕで個別に実行されます。使用可能な コゕがすべてゕプリケーションで使用されるため、順次実行よりも短時間でジョブ が完了します。 図 4 並列処理する for ... each の実装の出力
メモ: Parallel Extensions ラブラリには、静的 Parallel クラスからゕクセスする Invoke() という便利なメソッドもあります。このメソッドを使用すると、匿名メソ
ッドやラムダ式を並列実行できます。Invoke メソッドの使用方法を説明するため に、一般的なツリー処理ゕルゴリズムを示し、続いてこのゕルゴリズムを並列処理 して、ツリー全体の処理時間を短縮する方法について説明します。 この例では、従業員の階層を処理し、処理対象の従業員ごとに GetPayrollDeduction() メソッドを実行します。 19. Main() メソッドから現在呼び出しているメソッドを、Ex1Task1_WalkTree() メソッド に置き換えます。このコードでは、従業員階層のンスタンスを作成し、ツリー ウ ォーカー メソッドを呼び出します。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex1Task1_WalkTree(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call Ex1Task1_WalkTree() ...
EndSub
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 Ex1Task1_WalkTree CSharp) C#
private static void Ex1Task1_WalkTree() {
EmployeeHierarchy employeeHierarchy = new EmployeeHierarchy(); WalkTree(employeeHierarchy);
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 Ex1Task1_WalkTree VB) Visual Basic
Private Sub Ex1Task1_WalkTree()
Dim employeeHierarchy As New EmployeeHierarchy() WalkTree(employeeHierarchy)
20. Program クラスに次のメソッドを追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex1 WalkTree CSharp) C#
private static void WalkTree(Tree<Employee> node) {
if (node == null) return;
if (node.Data != null) {
Employee emp = node.Data;
Console.WriteLine("Starting process for employee id {0}", emp.EmployeeID);
decimal span = PayrollServices.GetPayrollDeduction(emp); Console.WriteLine("Completed process for employee id {0}", emp.EmployeeID); Console.WriteLine(); } WalkTree(node.Left); WalkTree(node.Right); }
(コード スニペット – Intro to Parallel Extensions Lab - Ex1 WalkTree VB) Visual Basic
Private Sub WalkTree(ByVal node As Tree(Of Employee)) If node Is Nothing Then
Return End If
If node.Data IsNot Nothing Then Dim emp As Employee = node.Data
Console.WriteLine("Starting process for employee id {0}", emp.EmployeeID) Dim span As Decimal = PayrollServices.GetPayrollDeduction(emp)
Console.WriteLine("Completed process for employee id {0}", emp.EmployeeID) Console.WriteLine() End If WalkTree(node.Left) WalkTree(node.Right) End Sub 21. ゕプリケーションをビルドして実行します。
22. 従業員は ID 順に処理されます。ツリーの処理に要した合計時間にも注目してくださ い (実際の時間は状況によって異なります)。
図 5
メモ: ツリーは構造化されているため、上記の並列処理しないゕルゴリズムでツリ
ーを処理すると、データが ID 順に出力されます。
23. ツリーを並列処理するには、WalkTree() メソッド最後の 2 つの WalkTree() 呼び出し を、静的 Parallel クラスの Invoke() メソッドに置き換えます。
C#
private static void WalkTree(Tree<Employee> node) {
if (node == null) return;
if (node.Data != null) {
Employee emp = node.Data;
Console.WriteLine("Starting process for employee id {0}", emp.EmployeeID);
decimal span = PayrollServices.GetPayrollDeduction(emp); Console.WriteLine("Completed process for employee id {0}", emp.EmployeeID);
Console.WriteLine(); }
Parallel.Invoke(delegate { WalkTree(node.Left); }, delegate { WalkTree(node.Right); }); }
Visual Basic
PrivateSub WalkTree(ByVal node AsTree(OfEmployee)) If node IsNothingThen
Return
EndIf
If node.Data IsNotNothingThen
Dim emp AsEmployee = node.Data
Console.WriteLine("Starting process for employee id {0}", emp.EmployeeID) Dim span AsDecimal = PayrollServices.GetPayrollDeduction(emp)
Console.WriteLine("Completed process for employee id {0}", emp.EmployeeID) Console.WriteLine()
EndIf
Parallel.Invoke(Sub() WalkTree(node.Left), Sub() WalkTree(node.Right))
EndSub
25. ツリー内の従業員が ID 順に処理されなくなり、他のノードの処理が完了する前に処 理が開始されるノードがあることがわかります。ツリー全体の処理時間も短縮され ています。
図 6
メモ: Invoke() メソッドでは、コゕが使用できるかどうかによって、WalkTree() への 各呼び出しのスケジュールを設定します。このため、ツリーが予測可能な方法で処 理されるとは限りません。コードの設計時にはこの点に注意が必要です。
次の手順:
演習 2: 並列タスクの作成と実行演習 2: 並列タスクの作成と実行
Parallel Extensions ラブラリには、複数のコゕで作業項目を並列処理するために使用できるTask クラスが用意されています。基本的に、Task オブジェクトは、TaskManager で必要と判
断されれば、他の作業単位と並列実行するようにスケジュールが設定される、簡易作業単位 と考えることができます。 Task オブジェクトを作成したら、実行するロジックを含むデリゲートやラムダ ステートメ ントを、作成したオブジェクトに提供する必要があります。次に、Parallel Extensions ラブ ラリの中核となる TaskManager が、Task の実行スケジュールを設定します。実行スケジュ ールは、別のコゕで実行中の別のスレッドに設定されることもあります。 メモ: 各手順を正しく実行していることを確認するために、各タスクの最後にソリューショ ンをビルドすることをお勧めします。 タスク 1 – 並列タスクを特別な設定なしに実行する
1. Microsoft Visual Studio 2010 を起動します。[スタート] ボタンをクリックし、[すべて のプログラム]、[Microsoft Visual Studio 2010]、[Microsoft Visual Studio 2010] の順にク リックします。
2.
%TrainingKitInstallationFolder%\Labs\IntroToParallelExtensions\Source\Ex02-CreateAndRunParallelizedTasks\begin フォルダーの C# フォルダーもしくは VB フォル
選択してください。) 前の演習で作成したソリューションから作業を続行することも できます。
3. Main() メソッドから現在呼び出しているメソッドを、Ex2Task1_NativeParallelTasks() メソッドに置き換えます。
C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex2Task1_NativeParallelTasks(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex2Task1_NativeParallelTasks() ...
EndSub
4. Ex2Task1_NativeParallelTasks メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex2 Ex2Task1_NativeParallelTasks CSharp)
C#
private static void Ex2Task1_NativeParallelTasks() {
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); }); Task task2 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); }); Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); }); }
(コード スニペット – Intro to Parallel Extensions Lab - Ex2 Ex2Task1_NativeParallelTasks VB)
Visual Basic
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2))) End Sub 5. ゕプリケーションをビルドして実行します。 6. 並列実行では、Ex2Task1_NativeParallelTasks メソッドが終了して Main メソッドに制 御が戻るまでに処理が完了しないタスクも存在します。Main メソッドに戻る前に完 了しなかったタスクがあるため、表示されている時間は合計処理時間ではありませ ん。 図 7 複数の並列タスクからの出力 タスク 2 – Wait() メソッドと WaitAll() メソッドを使用する タスクを並列実行するメリットは、実行時間の短縮と、マルチコゕ プロセッサの活用です。 しかし、タスク 1 の実装では、タスクを処理するスレッドが終了する前にメン ゕプリケ ーションが終了してしまうことがあります。 個別の Task オブジェクトで Wait() メソッドを呼び出すことで、このような状況に対処でき ます。その結果、メン スレッドは当該タスクの完了まで待機してから次の命令を続行す るようになります。 1. Main() メソッドから現在呼び出しているメソッドを、Ex2Task2_WaitHandling() メソ ッドに置き換えます。このコードは待機処理を追加します。 C#
static void Main(string[] args) {
// 呼び出すメソッド Ex2Task2_WaitHandling(); ...
}
Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex2Task2_WaitHandling() ...
EndSub
2. Ex2Task2_WaitHandling() メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に 追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandling CSharp) C#
private static void Ex2Task2_WaitHandling() {
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); }); Task task2 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); }); Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); }); task1.Wait();
task2.Wait(); task3.Wait(); }
(コード スニペット – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandling VB) C#
Private Sub Ex2Task2_WaitHandling()
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2))) task1.Wait()
task2.Wait() task3.Wait() End Sub
3. ゕプリケーションをビルドして実行します。 4. 終了日時を表示してメン スレッドが終了する前に、タスクが 3 つとも完了してい ます。 図 8 個別に Wait() 状態を使用する並列タスクの出力 メモ: メン スレッドは、作成した Task オブジェクトの完了を待機してから、処理 を続行します。これは、ThreadPool.QueueUserWorkItem を使用するよりもはるか に簡単かつ明確な方法です。QueueUserWorkItem メソッドを使用すると、リセット ベントを主導で作成および管理する必要が生じ、Interlocked 操作が追加される可 能性もあります。
5. 個別の Task オブジェクトの Wait() メソッド以外に、静的 Task クラスには WaitAll() メソッドもあり、タスクのリストを指定して、1 回の呼び出しでこれらのタスクの 完了を待機できます。このメソッドの動作を確認するには、task1、task2、および
task3 の各 Wait() 呼び出しを削除して、次のコードに置き換えます。
C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex2Task2_WaitHandlingWaitAll(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex2Task1_WaitHandlingWaitAll() ...
EndSub
6. Ex2Task2_WaitHandlingWaitingAll() メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandlingWaitAll CSharp)
C#
private static void Ex2Task2_WaitHandlingWaitAll() {
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); }); Task task2 = Task.Factory.StartNew (delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); }); Task task3 = Task.Factory.StartNew (delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); }); Task.WaitAll(task1, task2, task3);
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandlingWaitAll VB)
Visual Basic
Private Sub Ex2Task2_WaitHandlingWaitAll() Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2))) Task.WaitAll(task1, task2, task3)
End Sub
7. ゕプリケーションをビルドして実行します。
8. メン ゕプリケーションは、すべての Task の完了を待機してから続行します。
WaitAll() を使用する並列タスクの出力 タスク 3 – IsCompleted プロパティを使用する 他の処理を実行する前に Task オブジェクトの進行状況をチェックする場合 (たとえば、最初 のタスクが完了していなければ実行できない別のタスクがある場合)、Wait() メソッドを使 用すると、Task オブジェクトを起動したスレッド上での他のタスクの実行をブロックして しまうため、Wait() メソッドを使用したくないこともあるでしょう。このような場合に備え て、Task クラスでは IsCompleted プロパテゖを公開しています。このプロパテゖを使用する と、Task オブジェクトの処理が完了しているかどうかチェックしてから他の処理を続行で きます。 1. Main() メソッドから現在呼び出しているメソッドを、Ex2Task3_TaskIsCompleted() メ ソッドに置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex2Task3_TaskIsCompleted(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex2Task3_TaskIsCompleted() ...
EndSub
2. Ex2Task3_TaskIsCompleted() メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex2 Ex2Task3_TaskIsCompleted CSharp)
C#
private static void Ex2Task3_TaskIsCompleted() {
Task task1 = Task.Factory.StartNew(delegate { PayrollServices.GetPayrollDeduction(employeeData[0]); }); while (!task1.IsCompleted) { Thread.Sleep(1000); Console.WriteLine("Waiting on task 1"); }
Task task2 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); }); while (!task2.IsCompleted) { Thread.Sleep(1000); Console.WriteLine("Waiting on task 2"); }
Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); }); while (!task3.IsCompleted) { Thread.Sleep(1000); Console.WriteLine("Waiting on task 3"); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex2 Ex2Task3_TaskIsCompleted VB) Visual Basic
Private Sub Ex2Task3_TaskIsCompleted()
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) Do While Not task1.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 1") Loop
Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) Do While Not task2.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 2") Loop
Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2))) Do While Not task3.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 3") Loop
3. ゕプリケーションをビルドして実行します。 4. タスク 2 とタスク 3 は、前のタスクの IsCompleted プロパテゖが true になるまで開 始されません。 図 10 IsCompleted プロパテゖを使用する並列タスクの出力 タスク 4 – ContinueWith() メソッドを使用する IsCompleted プロパテゖは、Task オブジェクトにポーリングして終了しているかどうか調べ、 その後他のタスクを実行するのに役立ちますが、Task クラスにはもっと便利なオプション があります。ContinueWith() メソッドを使用すると、タスクを特定の順序で連続実行できま す。 ContinueWith() メソッドに引数として渡された機能は、Task オブジェクトのロジックが続行 されると実行されます。 1. Main() メソッドから現在呼び出しているメソッドを、Ex2Task4_ContinueWith() メソ ッドに置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex2Task4_ContinueWith(); ... } Visual Basic
...
' Methods to call
Ex2Task4_ContinueWith() ...
EndSub
2. Ex2Task4_ContinueWith() メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex2 Ex2Task4_ContinueWith CSharp) C#
private static void Ex2Task4_ContinueWith() {
Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); }) .ContinueWith(delegate { PayrollServices.GetPayrollDeduction(employeeData[1]); }) .ContinueWith(delegate { PayrollServices.GetPayrollDeduction(employeeData[2]); }); task3.Wait(); }
(コード スニペット – Intro to Parallel Extensions Lab - Ex2 Ex2Task4_ContinueWith VB) Visual Basic
Private Sub Ex2Task4_ContinueWith() Dim task3 As Task = Task.Factory _
.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) _ .ContinueWith(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) _ .ContinueWith(Sub() PayrollServices.GetPayrollDeduction(employeeData(2))) task3.Wait() End Sub メモ: ここでは、最初の Task オブジェクトを通常どおり作成していますが、 ContinueWith() メソッドを使用して、以降の呼び出しが順序どおりにランタムか ら実行されるようにしています。 3. ゕプリケーションをビルドして実行します。
図 11 ContinueWith により順序と待機状態を確保する並列タスクの出力
次の手順:
演習 3: Task<T> クラスを使用した値を返すタスクの作成と実行演習 3: Task<T> クラスを使用した値を
返すタスクの作成と実行
ご覧のように、Task オブジェクトは機能の単位を並列環境で起動するのに役立ちますが、 機能単位の実行結果として値を返すメカニズムも備えています。 この例を示すために、ここでは Task<decimal> の新しいンスタンスを作成し、静的 Task.Factory.StartNew() メソッドを使用して、戻り値を取得する方法で GetPayrollDeduction() メソッドを実行します。 タスク 1 – タスクの戻り値を取得する1. Microsoft Visual Studio 2010 を起動します。[スタート] ボタンをクリックし、[すべて のプログラム]、[Microsoft Visual Studio 2010]、[Microsoft Visual Studio 2010] の順にク リックします。
2.
%TrainingKitInstallationFolder%\Labs\IntroToParallelExtensions\Source\Ex03-UseTaskResult\begin フォルダーの C# フォルダーもしくは VB フォルダーにある ParallelExtLab.sln ソリューション フゔルを開きます。(お好みの言語を選択してく
3. Main() メソッドから現在呼び出しているメソッドを、Ex3Task1_TaskReturnValue() メ ソッドに置き換えます。
C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex3Task1_TaskReturnValue(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex3Task1_TaskReturnValue() ...
EndSub
4. Ex3Task1_TaskReturnValue() メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex3 Ex3Task1_TaskReturnValue CSharp)
C#
private static void Ex3Task1_TaskReturnValue() {
Console.WriteLine("Calling parallel task with return value"); var data = Task.Factory.StartNew(() =>
PayrollServices.GetPayrollDeduction(employeeData[0])); Console.WriteLine("Parallel task returned with value of {0}", data.Result);
}
(コード スニペット – Intro to Parallel Extensions Lab - Ex3 Ex3Task1_TaskReturnValue VB) Visual Basic
Private Sub Ex3Task1_TaskReturnValue()
Console.WriteLine("Calling parallel task with return value") Dim data As Task(Of Decimal) = Task.Factory.StartNew(Function() PayrollServices.GetPayrollDeduction(employeeData(0)))
Console.WriteLine("Parallel task returned with value of {0}", data.Result) End Sub
メモ: 値を取得するには、data.Result プロパテゖを調べます。Result プロパテゖの 呼び出し時にタスクが完了していれば、値がすぐに返されます。完了していなけれ ば、タスクが完了して値を取得できるようになるまで、実行中のコードがブロック されます。上記の例では、Result プロパテゖをすぐに呼び出していますが、これは 理想的な処理ではありません。Task<T> が非常に役立つのは、しばらくは戻り値を 取得しないような状況で作業単位を実行するときです。 5. ゕプリケーションをビルドして実行します。 6. タスクが完了し、戻り値が返されます。 図 12 Task を実行して戻り値を取得する場合の出力
次の手順:
演習 4: PLINQ を使用した LINQ クエリの並列化演習 4: PLINQ を使用した LINQ クエリ
の並列化
並列 LINQ (PLINQ) を使用すると、開発者は、LINQ クエリを並列環境での実行向けに最適化で きます。
Parallel Extensions ラブラリには、LINQ クエリに並列処理を実装する方法が多数用意されて います。PLINQ では、System.Linq.Enumerable クラスと同様の機能を提供する
タスク 1 – ParallelEnumerable クラスの静的メソッドを使用して LINQ を並列化する
このタスクでは、前の演習と同じソリューションを引き続き使用します。
1. Microsoft Visual Studio 2010 を起動します。[スタート] ボタンをクリックし、[すべて のプログラム]、[Microsoft Visual Studio 2010]、[Microsoft Visual Studio 2010] の順にク リックします。 2. %TrainingKitInstallationFolder%\Labs\IntroToParallelExtensions\Source\Ex04-PLINQ\begin フォルダーの C# フォルダーもしくは VB フォルダーにある ParallelExtLab.sln ソリューション フゔルを開きます。(お好みの言語を選択してく ださい。) 前の演習で作成したソリューションから作業を続行することもできます。 3. Main() メソッドから現在呼び出しているメソッドを、Ex4Task1_PLINQ() メソッドに 置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex4Task1_PLINQ(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call Ex4Task1_PLINQ() ...
EndSub
4. Ex4Task1_PLINQ () メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加 します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex4 Ex4Task1_PLINQ SCharp) C#
static void Ex4Task1_PLINQ() {
var q = Enumerable.Select( Enumerable.OrderBy(
Enumerable.Where(employeeData, x => x.EmployeeID % 2 == 0),
x => x.EmployeeID), x => PayrollServices.GetEmployeeInfo(x)) .ToList(); foreach (var e in q) { Console.WriteLine(e); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex4 Ex4Task1_PLINQ VB) Visual Basic
Private Sub Ex4Task1_PLINQ() Dim q = Enumerable.Select( Enumerable.OrderBy( Enumerable.Where( employeeData,
Function(x) x.EmployeeID Mod 2 = 0), Function(x) x.EmployeeID), Function(x) PayrollServices.GetEmployeeInfo(x)) _ .ToList() For Each e In q Console.WriteLine(e) Next e End Sub
メモ: Select() メソッド、OrderBy() メソッド、および Where() メソッドは
IEnumerable<T> クラスからの拡張メソッドですが、ここでは静的にゕクセスしてい ます。より簡潔な使用方法については、後で説明します。 ToList() 呼び出しは、説明を目的としており、運用コードには必ずしも必要ではあ りません。ここでは、LINQ クエリをすぐに実行してすべての従業員情報文字列を 収集し、後で画面に表示するために使用しています。 ToList() メソッドを省略する場合でも、クエリは EmployeeID 順に実行されますが、 GetEmployeeInfo() への各呼び出しは IEnumerable<T> が foreach ループで反復処理さ
れるまで実行されません。これを遅延実行と呼びます。
詳細については、Scott Wisniewski の記事 (http://msdn.microsoft.com/ja-jp/magazine/cc163378.aspx) を参照してください。
6. LINQ クエリで、EmployeeID 順に処理が実行されます。この処理の完了に要する合計 時間にも注目してください (実際の時間は状況によって異なります)。 図 13 並列処理しない LINQ クエリの出力 7. このクエリの並列化は簡単です。そのためには、静的 ParallelEnumerable クラスに含 まれる同等の LINQ メソッドを使用します。また、AsParallel() の呼び出しをクエリの データ ソースに追加することも必要です。Main() メソッドを変更して PLINQAsParallel メソッドを呼び出します。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex4Task1_PLINQAsParallel(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' 呼び出すメソッド Ex4Task1_PLINQAsParallel() ...
8. Ex4Task1_PLINQAsParallel () メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex4 Ex4Task1_PLINQAsParallel CSharp)
C#
static void Ex4Task1_PLINQAsParallel() { var q = ParallelEnumerable.Select( ParallelEnumerable.OrderBy( ParallelEnumerable.Where(employeeData.AsParallel(), x => x.EmployeeID % 2 == 0), x => x.EmployeeID), x => PayrollServices.GetEmployeeInfo(x)) .ToList(); foreach (var e in q) { Console.WriteLine(e); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex4 Ex4Task1_PLINQAsParallel VB) Visual Basic
Private Sub Ex4Task1_PLINQAsParallel() Dim q = ParallelEnumerable.Select( ParallelEnumerable.OrderBy( ParallelEnumerable.Where( employeeData.AsParallel(),
Function(x) x.EmployeeID Mod 2 = 0), Function(x) x.EmployeeID), Function(x) PayrollServices.GetEmployeeInfo(x)) _ .ToList() For Each e In q Console.WriteLine(e) Next e End Sub メモ: このタスクの前半では Enumerable 静的クラスで行われていた Select() メソッ ド、OrderBy() メソッド、および Where() メソッドの呼び出しが、 ParallelEnumerable クラスで実行されるようになりました。また、AsParallel() の呼 び出しがデータ ソースに追加されました。
9. ゕプリケーションをビルドして実行します。 10. LINQ クエリでは、処理が特定の順序で実行されなくなります。また、この例では、 並列処理されるクエリの実行時間は並列処理されない場合よりも短縮されます (この 場合はデュゕル コゕ コンピューターで実行しているため、実行時間がおよそ半減し ています。短縮される時間は、このサンプルを実行するハードウェゕによって異な ります)。 図 14 並列処理する LINQ クエリの出力 メモ: 並列に同時実行される操作の数は、使用可能な物理コゕ数に応じて増加しま す。 タスク 2 – ParallelEnumerable クラスの拡張メソッドを使用して LINQ を並列化する
前述の Enumerable クラスと ParallelEnumerable クラスの静的 LINQ メソッドをより簡潔に使 用するには、これらを拡張メソッドとして使用します。
1. 並列処理しない LINQ クエリを、拡張メソッドを使用して PLINQ クエリに変換するの は簡単です。次の LINQ クエリに一致するように、Main() メソッドの PLINQ クエリを 置き換えます。
C#
static void Main(string[] args) {
... // 呼び出すメソッド Ex4Task2_Extensions(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call Ex4Task2_Extensions() ...
EndSub
2. Ex4Task2_Extensions () メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に 追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex4 Ex4Task2_Extensions CSharp) C#
private static void Ex4Task2_Extensions() {
var q = employeeData.
Where(x => x.EmployeeID % 2 == 0).OrderBy(x => x.EmployeeID) .Select(x => PayrollServices.GetEmployeeInfo(x)) .ToList(); foreach (var e in q) { Console.WriteLine(e); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex4 Ex4Task2_Extensions VB) Visual Basic
Private Sub Ex4Task2_Extensions() Dim q = employeeData _
.Where(Function(x) x.EmployeeID Mod 2 = 0) _ .OrderBy(Function(x) x.EmployeeID) _ .Select(Function(x) PayrollServices.GetEmployeeInfo(x)) _ .ToList() For Each e In q Console.WriteLine(e) Next e End Sub
メモ: ここでも、ToList() を使用する目的は、Select() メソッドから返される
IEnumerable<T> がこの後の foreach ループで反復処理されるのを待たずに、LINQ ク
エリをすぐに実行することです。これにより遅延実行を回避しています。 3. ゕプリケーションをビルドして実行します。 4. LINQ クエリで、EmployeeID 順に処理が実行されます。この処理の完了に要する合計 時間にも注目してください (実際の時間は状況によって異なります)。 図 15 拡張メソッドを使用した並列処理しない LINQ クエリの出力 5. この LINQ クエリを並列処理するには、Main() メソッドから現在呼び出しているメソ ッドを、AsParallel() メソッドに置き換えるだけです。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex4Task2_ConvertToParallelExtensions(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
...
EndSub
6. Ex4Task2_ConvertToParallelExtensions () メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex4 Ex4Task2_ConvertToParallelExtensions CSharp)
C#
private static void Ex4Task2_ConvertToParallelExtensions() {
var q = employeeData.AsParallel()
.Where(x => x.EmployeeID % 2 == 0).OrderBy(x => x.EmployeeID) .Select(x => PayrollServices.GetEmployeeInfo(x)) .ToList(); foreach (var e in q) { Console.WriteLine(e); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex4 Ex4Task2_ConvertToParallelExtensions VB)
Visual Basic
Private Sub Ex4Task2_ConvertToParallelExtensions() Dim q = employeeData.AsParallel() _
.Where(Function(x) x.EmployeeID Mod 2 = 0) _ .OrderBy(Function(x) x.EmployeeID) _ .Select(Function(x) PayrollServices.GetEmployeeInfo(x)) _ .ToList() For Each e In q Console.WriteLine(e) Next e End Sub 7. ゕプリケーションをビルドして実行します。 8. ParallelEnumerable 静的クラスに基づく LINQ クエリと同様に、拡張メソッドとして 実装される PLINQ クエリでは、処理が EmployeeID の順に実行されなくなります。並 列に同時実行される操作の数は、使用可能な物理コゕ数に応じて増加します。また、
タスク 1 の並列 LINQ の例と同様に、並列処理しないクエリと比べて、並列処理する クエリの実行時間はおよそ半減します。
図 16
拡張メソッドを使用した並列処理する LINQ クエリの出力
タスク 3 – AsParallel() をクエリの包含構文と併用する
このタスクでは、Parallel Extensions ラブラリと AsParallel() メソッドを使用して、クエリの 包含構文を使用する並列 LINQ クエリを作成します。
1. Main() メソッドの LINQ クエリを、次のクエリの包含構文に置き換えます。 C#
static void Main(string[] args) { ... // 呼び出すメソッド Ex4Task3_PLINQComprehensionSyntax(); ... } Visual Basic
Sub Main(ByVal args() AsString) ...
' Methods to call
Ex4Task3_PLINQComprehensionSyntax() ...
2. Ex4Task2_ConvertToParallelExtensions () メソッドを Program.cs (C#) または Module1.vb (Visual Basic) に追加します。
(コード スニペット: Intro to Parallel Extensions Lab - Ex4 Ex4Task3_PLINQComprehensionSyntax CSharp)
C#
private static void Ex4Task3_PLINQComprehensionSyntax() {
var q = from e in employeeData.AsParallel() where e.EmployeeID % 2 == 0 orderby e.EmployeeID select PayrollServices.GetEmployeeInfo(e); foreach (var e in q) { Console.WriteLine(e); } }
(コード スニペット – Intro to Parallel Extensions Lab - Ex4 Ex4Task3_PLINQComprehensionSyntax VB)
Visual Basic
Private Sub Ex4Task3_PLINQComprehensionSyntax() Dim q = From e In employeeData.AsParallel() Where e.EmployeeID Mod 2 = 0
Order By e.EmployeeID Select PayrollServices.GetEmployeeInfo(e) For Each e In q Console.WriteLine(e) Next e End Sub 3. ゕプリケーションをビルドして実行します。 4. LINQ 構文が変更されても、ParallelEnumerable の拡張メソッドの場合と同じ並列手法 でデータが処理されることがわかります。
図 17 クエリの包含構文を使用した並列処理する LINQ クエリの出力
次の手順:
まとめまとめ
このラボでは、簡単で制御しやすい方法で並列タスクを処理するのに役立つ機能について理 解するために、Parallel Extensions ラブラリを操作しました。Parallel、Task といった Parallel Extensions のクラスを使用して作業単位を管理する方法について学習しました。 Wait()、WaitAll()、IsComplete()、ContinueWith() などの Parallel Extensions 機能を利用して処理 の流れを制御しました。また、PLINQ を使用してクエリを並列処理する例についても学習し ました。このラボでは、Parallel Extensions ラブラリを紹介し、そのラブラリの効果とメリットに ついて概説しました。詳細については、以下の Web サトを参照してください。
MSDN の Parallel Extensions ブログ (英語): http://blogs.msdn.com/pfxteam/
MSDN の並列コンピューテゖング フォーラム (英語):
Parallel Computing Developer Center (英語): http://msdn.microsoft.com/en-us/concurrency/default.aspx