すべての並列処理タスクには、タスクの調整によるオーバーヘッドがいくらかあります。 pmap
別のスレッドで各要素に個別にマッピング関数を適用します。によって返された遅延シーケンスpmap
が消費されると、消費者スレッドは生産者スレッドと調整する必要があります。方法pmap
が定義されており、このオーバーヘッドは、生成されるすべての要素に対して発生します。
これを考慮pmap
すると、単純な関数 (例のように数値を 2 乗するなど) を計算するために使用する場合、スレッドがアクティビティを調整するのにかかる時間は、実際に値を計算するのにかかる時間を圧倒します。docstring が言うように、 「 f の時間が調整のオーバーヘッドを支配する計算集約型pmap
の関数にのみ役立ちます」(エンパシスが追加されています)。このような場合、コアの数に関係なく、より時間がかかります。pmap
map
から実際に利益を得るにはpmap
、「より難しい」問題を選択する必要があります。場合によっては、これは入力シーケンスをチャンクに分割するのと同じくらい簡単かもしれません。次に、チャンクのシーケンスを処理しpmap
て実行しconcat
、最終的な出力を得ることができます。
例えば:
(defn chunked-pmap [f partition-size coll]
(->> coll ; Start with original collection.
(partition-all partition-size) ; Partition it into chunks.
(pmap (comp doall ; Map f over each chunk,
(partial map f))) ; and use doall to force it to be
; realized in the worker thread.
(apply concat))) ; Concatenate the chunked results
; to form the return value.
ただし、シーケンスを分割し、最後にチャンクを連結するためのオーバーヘッドもあります。たとえば、少なくとも私のマシンでは、あなたの例ではchunked-pmap
まだmap
かなりのパフォーマンスが低下しています。それでも、一部の機能では有効な場合があります。
の有効性を向上させるもう 1 つの方法pmap
は、アルゴリズム全体の別の場所で作業を分割することです。たとえば、点のペア間のユークリッド距離の計算に関心があるとします。二乗関数の並列化は効果がないことが証明されていますが、距離関数全体を並列化することで運が良くなるかもしれません。現実的には、タスクをさらに高いレベルで分割したいと考えていますが、それが要点です。
つまり、並列アルゴリズムのパフォーマンスは、タスクが分割される方法に敏感であり、テストには細かすぎるレベルを選択しました。