KZKY memo

自分用メモ.

PythonにおけるShared Memory

前提

pythonはGILの影響でmulti thread programmingでcpu-bound jobが早くならない.
なので,multiprocessingを使うしかない.

CPythonのmultiprocessingはforkなので,unixならcopy-on-write.なので,globで定義したデータなら,Read-onlyに限り,特段気にしないで共有メモリでタスクがパラレルに使えるはずというのは勘違いのよう.この場合は,ref-countが変わって結局コピーが起こるそう.

結局のところ(multiprocessing documentにあるように), shared memory (Value, Array, RawArray)を使って,データを受け渡すしかないよう.Queue/Pipe経由ではなく,os.forkの前に受け渡す.Arrayはdefaultでlockがあるので,lockを気にしないならRawArrayを使う.

実験環境

  • CPU: Intel(R) Xeon(R) CPU X5680 @ 3.33GHz
  • Mem: 52 GB
  • Disk: ST3500418AS
  • OS: ubuntu14.04

Read-onlyなタスク

タスクは,pairwise-similarity (pairwise-innerproduct)を使い,愚直にnumpyで2 loopsを回す.(10000, 100)の行列で,2回10000のloopでdot productをとる.

ここは,numbaを使う,こんなことやらずに,numpyで計算方法の工夫をするなどが考えられるが,それは,out-of-scope.numbaは,python: 行列演算の高速化を参考にされたい.

行いたい比較検証は下記のとおり

1. 1processでnumpyの計算を行う
2. sharedctypes.RawArray + np.ctypeslibで,2と同じことを行う
3. sharedmemを使う

これらで計算速度を比較する

それぞれの検証結果のコードはここ

各実験を10回実行した時の平均,パラでやっている場合は,最大値をとってからの平均.

結果

Exp. index Elapsed time (sec)
1 123.8867863655
2 32.0695706606
3 129.2636404037

Writeありなタスク

タスクは,Read-onlyなタスクと同じで,pairwise-similarity (pairwise-innerproduct)だが,結果を共有メモリに書き出す.

行いたい比較検証は下記の通り

1. sharedctypes.Array + np.ctypeslibで書き込まれるobjectを作る
2. sharedctypes.RawArray + np.ctypeslibで書き込まれるobjectを作る
3. sharedmemで書き込まれるobjectを作る

元のデータは,Read-onlyなタスクでRawArray > sharememだったので,RawArrayで共有する.

これらで計算速度を比較する

それぞれの検証結果のコードはここ

各実験を10回実行した時の平均,パラでやっている場合は,最大値をとってからの平均.

結果

Exp. index Elapsed time (sec)
1 37.442804575
2 37.6960495472
3 38.0742048979

まとめ

ReadもWriteも予想どおりスピードは,#concurrency倍になったが,sharedmemをreadソースとして使った時になぜか,baseの実験(read1)と同じ実行時間になってしまった..., 中身が,mmap.mmapなのが原因なのか...? 

それにしては,baseの実験(read1)と同じくらいの実行時間になってしまったことが気がかり...