私は F# で計算集約的な作業を行ってきました。.Net Task Parallel Library を使用するようなArray.Parallel.map
関数は、非常に最小限の労力で私のコードを指数関数的に高速化しました。
ただし、メモリの問題により、コードのセクションを作り直して、シーケンス式内で遅延評価できるようにしました (これは、格納して渡す情報が少なくなることを意味します)。評価する時が来たとき、私は以下を使用しました:
// processor and memory intensive task, results are not stored
let calculations : seq<Calculation> = seq { ...yield one thing at a time... }
// extract results from calculations for summary data
PSeq.iter someFuncToExtractResults results
それ以外の:
// processor and memory intensive task, storing these results is an unnecessary task
let calculations : Calculation[] = ...do all the things...
// extract results from calculations for summary data
Array.Parallel.map someFuncToExtractResults calculations
Array.Parallel 関数のいずれかを使用すると、コンピューターのすべてのコアがギアを上げていることがはっきりとわかります (~100% の CPU 使用率)。ただし、追加のメモリが必要になるということは、プログラムが終了しないことを意味します。
プログラムを実行したときの PSeq.iter バージョンでは、約 8% の CPU 使用率 (および最小限の RAM 使用率) しかありません。
では、PSeq バージョンの実行速度がこれほど遅いのには何か理由があるのでしょうか? 遅延評価のせいですか?私が見逃している魔法の「平行になる」ものはありますか?
ありがとう、
その他のリソース、両方のソース コード実装 (.NET では異なる Parallel ライブラリを使用しているようです):
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/array.fs
https://github.com/fsharp/powerpack/blob/master/src/FSharp.PowerPack.Parallel.Seq/pseq.fs
編集:コード例と詳細に詳細を追加
コード:
シーケンス
// processor and memory intensive task, results are not stored let calculations : seq<Calculation> = seq { for index in 0..data.length-1 do yield calculationFunc data.[index] } // extract results from calculations for summary data (different module) PSeq.iter someFuncToExtractResults results
配列
// processor and memory intensive task, storing these results is an unnecessary task let calculations : Calculation[] = Array.Parallel.map calculationFunc data // extract results from calculations for summary data (different module) Array.Parallel.map someFuncToExtractResults calculations
詳細:
- 中間アレイ バージョンの保存は 10 分未満で (クラッシュする前に取得できる限り) 高速に実行されますが、クラッシュする前に ~70GB の RAM を使用します (64GB 物理、残りはページング)。
- seq バージョンは 34 分以上かかり、RAM の一部 (約 30GB のみ) を使用します。
- 私が計算している〜十億の値があります。したがって、10 億倍 (それぞれ 64 ビット) = 7.4505806GB です。より複雑な形式のデータがあります...そしていくつかの不要なコピーをクリーンアップしているため、現在大量の RAM が使用されています。
- はい、アーキテクチャは良くありません。遅延評価は、プログラムを最適化したり、データを小さなチャンクにまとめたりする最初の部分です。
- より小さいデータセットでは、コードの両方のチャンクが同じ結果を出力します。
- @pad、私はあなたが提案したことを試しました.PSeq.iterはCalculation []を供給されたときに適切に動作するように見えました(すべてのコアがアクティブです)が、まだRAMの問題があります(最終的にクラッシュしました)
- コードの要約部分と計算部分の両方が CPU を集中的に使用します (主にデータ セットが大きいため)。
- Seq バージョンでは、一度だけ並列化することを目指しています