実行ポリシー
C++17 parallel algorithmsで第一引数に与える実行ポリシー(execution policy)は、seq, par, par_unseqの3つがヘッダ:<execution>で名前空間std::executionに定義されています。
seq(sequential)は従来通りの順次実行、par(parallel)が並列実行、par_unseq(parallel un-sequential)は並列実行に加えSSE/AVX等のSIMD命令によるベクトル化らしいです。
<algorithm>と<numeric>に定義されたほとんどの汎用/数値アルゴリズムに実行ポリシーを与えることができます。
しかしながら、これらアルゴリズムのすべてが実行ポリシー:par/par_unseqを与えることで並列化されるわけではありません。
前述のVisual C++開発チームのblogによりますと、並列化されるアルゴリズム(関数)は以下のとおり:
| adjacent_difference | find_first_of | search |
| adjacent_find | find_if | search_n |
| all_of | for_each | sort |
| any_of | for_each_n | stable_sort |
| count | inclusive_scan | transform |
| count_if | mismatch | transform_exclusive_scan |
| equal | none_of | transform_inclusive_scan |
| exclusive_scan | reduce | transform_reduce |
| find | remove | |
| find_end | remove_if |
上記以外のアルゴリズムはpar/par_unseqを与えてもseq(順次実行)と見なされます。並列化されない/できないワケはいくつかあって:
並列化による効果が見込めない
処理自体が単純な代入/コピーや入れ替えであり、複数を同時に行ったところで。パフォーマンスはメモリーのバンド幅で頭打ちになってしまいます。
| copy | move_backward | reverse_copy |
| copy_backward | remove | rotate |
| copy_n | remove_if | rotate_copy |
| fill | replace | swap_ranges |
| fill_n | replace_if | |
| move | reverse |
並列化された処理がユーザの期待に添わない
例えば、
int n = 0;
auto even = [&]() { return n += 2; }; // 2,4,6...を返す
array<int,N> data;
generate_n(data.begin(), N, even);
の場合、dataには2,4,6...が順にセットされることを期待してるはずで、並列化するとその期待を裏切る結果となるでしょうから。
| generate |
| generate_n |
効率的に並列化できそうにない
| partial_sort |
| partial_sort_copy |
並列化による効果が見込めるか、現時点では評価されていない
将来的に並列化される"かもしれない"。
| copy_if | max_element | replace_copy_if |
| includes | merge | set_difference |
| inplace_merge | min_element | set_intersection |
| is_heap | minmax_element | set_symmetric_difference |
| is_heap_until | nth_element | set_union |
| is_partitioned | partition_copy | stable_partition |
| is_sorted | remove_copy | unique |
| is_sorted_until | remove_copy_if | unique_copy |
| lexicographical_compare | replace_copy |
並列化されないアルゴリズムにpar/par_unseqを与えても、warning/errorとはならないみたいです。
