インテル® C++ コンパイラー XE 13.1 ユーザー・リファレンス・ガイド
プログラムを開発する際、安全性、正当性、パフォーマンスに関する次の考察に留意してください。
レデューサーとビュー
レデューサーはビューのインスタンスを管理します。並列リダクション処理のコードは、現在の並列ストランド用にビュー・インスタンスを更新します。現在のビュー・インスタンスには、レデューサーを逆参照することでアクセスできます (例: *r = *r OP a)。
つまり、レデューサーはビューへのポインターとして考えることができます。
一部のライブラリー・レデューサーは、* 演算子なしでレデューサーに操作を適用することを許可しています (例: r = r OP a)。 この表記法は下位互換性のためにサポートされていますが、ビューの参照操作が行われていることが不明瞭です。新しいコードでは、常にレデューサーを逆参照してビューにアクセスしてください (例: *reducer)。
安全性
前述のように適切に記述されたレデューサーを使用すると、異なる並列ストランド間によるレデューサーのビューへのアクセスにおいてデータ競合は発生しません。
浮動小数点演算
浮動小数点算術演算では、コンピューターの浮動小数点数の表現方法により、オーバーフロー、アンダーフロー、そして精度の低下が発生するため、厳密には結合則を満たしていません。これは、レデューサーを含む、浮動小数点演算を再結合する最適化に影響する可能性があります。
浮動小数点型のレデューサーを使用する前に、データの特性と結果への影響を慎重に検証してください。
初期値と最終値
レデューサーの初期値は、レデューサーのコンストラクターへの引数として、またはレデューサーの set_value() 関数を呼び出して指定できます。 初期値を指定しない場合、レデューサーのデータ型のデフォルト値が使用されます。初期値は必ずしも単位元と同じになるとは限りません。
計算の最終値は、計算が終了した後に get_value() 関数を呼び出して取得できます。
get_value() と set_value() は、常に現在のストランドのビュー・インスタンスにアクセスします。 これらの関数を並列処理中に呼び出すことはできますが、ほとんどの場合意味がありません。set_value() はレデューサーの初期化のみに使用し、get_value() は最終値の取得のみに使用すべきです。
許可される操作
リダクション操作が結合則を満たしているため、レデューサーは並列処理で正しい結果 (つまり、シリアル処理と同じ結果) を計算します。結合則を満たしていない処理の結合は意図しない結果につながります。つまり、レデューサーのビューで許可される変更は、リダクション操作による更新 (view = view OP value) またはセマンティクス的に等価な操作のみです。 (例えば、加算レデューサーでは次の操作が許可されます: view = view + value、 view += value (view = view + value と等価)、view++ (view = view + 1 と等価)、および view = view - value (view = view + (- value) と等価)。)
すべてのライブラリー・レデューサー・クラスには次の制約があります: view = view * value または view = value - view は、view が加算レデューサーのビューの場合コンパイルされません。 カスタム・レデューサー・クラスにも同様の制約がある場合があります。ビューで許可される操作が構文で制約されていないレデューサー・クラスを使用する場合、演算子の制約を理解し、それに従うのは開発者の責任です。
パフォーマンス
レデューサーを適切に使用すると、ランタイムのパフォーマンス低下はほとんど、あるいはまったくありません。ただし、パフォーマンスについては、以下のことを考慮しなければなりません。
レデューサーの効率は、ビューの作成とマージにはオーバーヘッドがほとんどかからないという仮定に基づいています。単位元と reduce 操作の実行時間が小さく一定でない場合、ビューの管理に伴うオーバーヘッドにより並列実行の利点は失われます。
新しいビュー・インスタンスが作成されたかどうかに関係なく、すべてのレデューサーにおいてストランドが同期される cilk_sync でオーバーヘッドが発生します。 多数のレデューサー (例えば、大きなレデューサーの配列) を使用する場合は、これが重要になることがあります。