このページは、ベータ版用に機械翻訳されたものです。翻訳者による翻訳は、製品の正規版で提供される予定です。詳細についてはよくある質問 を参照してください。またぜひこちら からアンケートにもご協力ください。
Visual Studio 2010 - Visual C++
チュートリアル: タスク グループを使用してパフォーマンスを向上するには

[このドキュメントはプレビュー版であり、後のリリースで変更されることがあります。 空白のトピックは、プレースホルダーとして挿入されています。]

このチュートリアルでは、作業グループを使用して、bitonic 並べ替えアルゴリズムのパフォーマンスを向上させる方法について説明します。 bitonic の [並べ替えアルゴリズム再帰的には入力シーケンスを小さい並べ替えられたパーティションに分割します。 bitonic の並べ替えアルゴリズムは各パーティションの操作が他のすべての操作とは無関係で並列実行できます。

並べ替え入力シーケンスのすべての組み合わせを並べ替えますネットワーク の例を bitonic の並べ替えには、次の使用例シーケンスの長さが 2 の累乗を並べ替えます。

セクション

このチュートリアルでは、次のタスクについて説明します。

直列 Bitonic 並べ替えを実行します。

次の使用例は、bitonic の並べ替えアルゴリズムのシリアル バージョンを表示します。 bitonic_sort 関数はシーケンスを 2 つのパーティションに分割し、反対方向は、これらのパーティションを並べ替えますをし、結果を結合します。 この関数は各パーティションの並べ替えに 2 回繰り返し自体呼び出します。

Visual C++
const bool INCREASING = true;
const bool DECREASING = false;

// Comparator function for the bitonic sort algorithm.
template <class T>
void compare(T* items, int i, int j, bool dir)
{
   if (dir == (items[i] > items[j]))
   {
      swap(items[i], items[j]);
   }
}

// Sorts a bitonic sequence in the specified order.
template <class T>
void bitonic_merge(T* items, int lo, int hi, bool dir)
{
   if (hi > 1)
   {
      int m = hi / 2;
      for (int i = lo; i < lo + m; ++i)
      {
         compare(items, i, i + m, dir);
      }
      bitonic_merge(items, lo, m, dir);
      bitonic_merge(items, lo + m, m, dir);
   }
}

// Sorts the given sequence in the specified order.
template <class T>
void bitonic_sort(T* items, int lo, int hi, bool dir)
{
   if (hi > 1)
   {
      // Divide the array into two partitions and then sort 
      // the partitions in different directions.
      int m = hi / 2;
      bitonic_sort(items, lo, m, INCREASING);
      bitonic_sort(items, lo + m, m, DECREASING);

      // Merge the results.
      bitonic_merge(items,lo, hi, dir);
   }
}

// Sorts the given sequence in increasing order.
template <class T>
void bitonic_sort(T* items, int size)
{
    bitonic_sort(items, 0, size, INCREASING);
}

[go to top]

Bitonic の並べ替えを実行する structured_task_group をパラレルでください。

ここでは、structured_task_group オブジェクトを使用して bitonic 並べ替えアルゴリズムを並列で実行する方法について説明します。

手順

bitonic 並べ替えアルゴリズムを並列で実行するには

  1. ヘッダー ファイル ppl.h の #include ディレクティブを追加します。

  2. using 名前空間の Concurrency ディレクティブを追加します。

  3. bitonic_merge 関数でその関数に、再帰関数呼び出しを削除します。

  4. 並列で、シーケンスをマージする structured_task_group オブジェクトを作成します。

    Visual C++
    structured_task_group tg;
    
  5. タスク グループに最初のシーケンスを結合する作業関数を含む、task_handle オブジェクトを作成します。

    Visual C++
    auto task = make_task([&] {
       bitonic_merge(items, lo, m, dir);
    });
    
  6. 最初のタスクの実行を開始する structured_task_group::run メソッドを呼び出します。

    Visual C++
    tg.run(task);
    
  7. 呼び出しコンテキストに 2 つ目のパーティションのマージします。

    Visual C++
    bitonic_merge(items, lo + m, m, dir);
    
  8. 最初のタスクを完了するまで待機する structured_task_group::wait メソッドを呼び出します。

    Visual C++
    tg.wait();
    
  9. 1 つ前の手順では、bitonic_sort 関数のようなプロセスを実行します。

    Visual C++
    structured_task_group tg;
    
    auto task = make_task([&] {
       parallel_bitonic_sort(items, lo, m, INCREASING);
    });
    
    tg.run(task);
    
    parallel_bitonic_sort(items, lo + m, m, DECREASING);
    
    tg.wait();
    

次の完全な例では、シリアルと bitonic 並べ替えアルゴリズムの並列バージョンの両方を実行します。 使用例もコンソールに出力の各計算を実行する必要な時間。

Visual C++
// parallel-bitonic-sort.cpp
// compile with: /EHsc
#include <windows.h>
#include <algorithm>
#include <iostream>
#include <ppl.h>

using namespace Concurrency;
using namespace std;

// Calls the provided work function and returns the number of milliseconds 
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
   __int64 begin = GetTickCount();
   f();
   return GetTickCount() - begin;
}

const bool INCREASING = true;
const bool DECREASING = false;

// Comparator function for the bitonic sort algorithm.
template <class T>
void compare(T* items, int i, int j, bool dir)
{
   if (dir == (items[i] > items[j]))
   {
      swap(items[i], items[j]);
   }
}

// Sorts a bitonic sequence in the specified order.
template <class T>
void bitonic_merge(T* items, int lo, int hi, bool dir)
{
   if (hi > 1)
   {
      int m = hi / 2;
      for (int i = lo; i < lo + m; ++i)
      {
         compare(items, i, i + m, dir);
      }
      bitonic_merge(items, lo, m, dir);
      bitonic_merge(items, lo + m, m, dir);
   }
}

// Sorts the given sequence in the specified order.
template <class T>
void bitonic_sort(T* items, int lo, int hi, bool dir)
{
   if (hi > 1)
   {
      // Divide the array into two partitions and then sort 
      // the partitions in different directions.
      int m = hi / 2;
      bitonic_sort(items, lo, m, INCREASING);
      bitonic_sort(items, lo + m, m, DECREASING);

      // Merge the results.
      bitonic_merge(items,lo, hi, dir);
   }
}

// Sorts the given sequence in increasing order.
template <class T>
void bitonic_sort(T* items, int size)
{
    bitonic_sort(items, 0, size, INCREASING);
}

// Sorts a bitonic sequence in the specified order.
template <class T>
void parallel_bitonic_merge(T* items, int lo, int hi, bool dir)
{
   // Merge the sequences concurrently if there is sufficient work to do.
   if (hi > 500)
   {
      int m = hi / 2;
      for (int i = lo; i < lo + m; ++i)
      {
         compare(items, i, i + m, dir);
      }

      // Use a structured task group to merge the sequences in parallel.
      structured_task_group tg;

      // Use the task group to merge the first sequence.
      auto task = make_task([&] {
         parallel_bitonic_merge(items, lo, m, dir);
      });
      tg.run(task);

      // Merge the second partition on the calling context.
      parallel_bitonic_merge(items, lo + m, m, dir);

      // Wait for the first task to complete.
      tg.wait();
   }
   // Otherwise, perform the work serially.
   else if (hi > 1)
   {
      bitonic_merge(items, lo, hi, dir);
   }
}

// Sorts the given sequence in the specified order.
template <class T>
void parallel_bitonic_sort(T* items, int lo, int hi, bool dir)
{   
   if (hi > 1)
   {
      // Divide the array into two partitions and then sort 
      // the partitions in different directions.
      int m = hi / 2;

      // Use a structured task group to sort the partitions in parallel.
      structured_task_group tg;

      // Use the task group to sort the first partition.
      auto task = make_task([&] {
         parallel_bitonic_sort(items, lo, m, INCREASING);
      });
      tg.run(task);

      // Sort the second partition on the calling context.
      parallel_bitonic_sort(items, lo + m, m, DECREASING);

      // Wait for the first task to complete.
      tg.wait();

      // Merge the results.
      parallel_bitonic_merge(items, lo, hi, dir);
   }
}

// Sorts the given sequence in increasing order.
template <class T>
void parallel_bitonic_sort(T* items, int size)
{
   parallel_bitonic_sort(items, 0, size, INCREASING);
}

int wmain()
{  
   // For this example, the size must be a power of two.
   const int size = 0x200000;

   // Create two large arrays and initialize them with random values.
   int* a1 = new int[size];
   int* a2 = new int[size];

   srand(42);
   for(int i = 0; i < size; ++i)
   {
      a1[i] = a2[i] = rand();
   }

   __int64 elapsed;

   // Perform the serial version of the sort.
   elapsed = time_call([&] { bitonic_sort(a1, size); });
   wcout << L"serial time: " << elapsed << endl;

   // Now perform the parallel version of the sort.
   elapsed = time_call([&] { parallel_bitonic_sort(a2, size); });
   wcout << L"parallel time: " << elapsed << endl;

   delete[] a1;
   delete[] a2;
}

次の出力サンプルでは、4 つのプロセッサをあるコンピューターのです。

serial time: 4353
parallel time: 1248

[go to top]

コードのコンパイル

コードをコンパイルするには、コピー、Visual Studio プロジェクトに貼り付けるしたりという名前の並列-bitonic-sort.cpp の され Visual Studio コマンド プロンプト ウィンドウで、次のコマンドを実行しされるファイルに貼り付けます。

cl.exe /EHsc parallel-bitonic-sort.cpp

信頼性の高いプログラミング

次の使用例は各作業グループの有効期間は、関数を超えて拡張しないため、task_group structured_task_group クラスの代わりに、 クラスを使用します。 できます、structured_task_group オブジェクトよりもオーバーヘッドが小さい実行があるように適切に実行するコードを記述するためので、ときに task group オブジェクトを使用することを推奨します。

structured_task_group クラスを使用する場合は手動でに オブジェクトの task_handle を作成し、 task_handle オブジェクトの終了後に各 structured_task_group オブジェクトのデストラクターが実行されることを確認する必要があります。 この例では、make_task ヘルパー関数を使用して task_handle オブジェクトを作成します。

次の使用例は、呼び出し元のコンテキストで最後の一連のタスクを実行してオーバーヘッドが減少します。 たとえば、bitonic_merge に最初の呼び出し、作業グループで、2 番目の呼び出し、呼び出し元のコンテキストで実行されます。

一部のアルゴリズムの並列バージョンを行うには十分な処理がある場合にのみより実行します。 たとえば、parallel_bitonic_merge 関数シーケンスに 500 または少ない要素がある場合は、シリアル バージョン bitonic_merge を呼び出します。

参照

参照

概念

Page view tracker