web-dev-qa-db-ja.com

タスクベースのプログラミング:#pragma omptaskと#pragmaomp parallel for

検討中:

    void saxpy_worksharing(float* x, float* y, float a, int N) {
      #pragma omp parallel for
      for (int i = 0; i < N; i++) {
         y[i] = y[i]+a*x[i];
      }
    }

そして

    void saxpy_tasks(float* x, float* y, float a, int N) {
      #pragma omp parallel
      {
         for (int i = 0; i < N; i++) {
         #pragma omp task
         {
           y[i] = y[i]+a*x[i];
         }
      }
   }

タスクとompparallelディレクティブを使用した場合の違いは何ですか?マージソートなどの再帰的アルゴリズムをタスクで記述できるのに、ワークシェアリングでは記述できないのはなぜですか?

13
user1511956

ローレンスリバモア国立研究所のOpenMPチュートリアルをご覧になることをお勧めします ここ

あなたの特定の例は、OpenMPタスクを使用してnot実装されるべきではない例です。 2番目のコードはスレッドタスクの数のN倍を作成し(欠落している}の横にあるコードにエラーがあるため、後で戻ってきます)、各タスクは非常に単純な計算。 この質問 に対する私の回答でわかるように、タスクのオーバーヘッドは巨大になります。それに加えて、2番目のコードは概念的に間違っています。ワークシェアリングディレクティブがないため、すべてのスレッドがループのすべての反復を実行し、Nタスクの代わりに、N倍のスレッドタスクが作成されます。次のいずれかの方法で書き直す必要があります。

シングルタスクプロデューサー-一般的なパターン、NUMAは非友好的:

void saxpy_tasks(float* x, float* y, float a, int N) {
   #pragma omp parallel
   {
      #pragma omp single
      {
         for (int i = 0; i < N; i++)
            #pragma omp task
            {
               y[i] = y[i]+a*x[i];
            }
      }
   }
}

singleディレクティブは、ループを単一のスレッド内でのみ実行します。他のすべてのスレッドはそれをスキップし、single構文の最後にある暗黙のバリアにぶつかります。バリアには暗黙的なタスクスケジューリングポイントが含まれているため、待機中のスレッドは、タスクが使用可能になるとすぐに処理を開始します。

並列タスクプロデューサー-よりNUMAフレンドリー:

void saxpy_tasks(float* x, float* y, float a, int N) {
   #pragma omp parallel
   {
      #pragma omp for
      for (int i = 0; i < N; i++)
         #pragma omp task
         {
            y[i] = y[i]+a*x[i];
         }
   }
}

この場合、タスク作成ループはスレッド間で共有されます。

NUMAが何であるかわからない場合は、NUMAの使いやすさに関するコメントは無視してください。

25
Hristo Iliev