Python
- Multi - Thred [1]
- 同一CPUでメモリを共有
- メモリの書き込みや読み込み (I/O処理)でタイミングの処理が重要
- Multi - Process
- それぞれのCPUでメモリは共有されない
pythonでは,グローバルインタプリタロック (GIL)によって,1プロセッサ当り1スレッドの実行に制限される.このため計算処理の多いプログラムにマルチスレッドを設定しても,予想通りにパフォーマンスが上がらないことがある [2].
よって,コードを走らせる前に,スレッド数とコア数を確認した方が良い.
GILを回避するためには、mpi4pyを使うか、Cで書かれている高速ライブラリのNumpy, Scipyを使用する関数内でGILの効かない並列化を行うのが効率が良い.
I/Oに時間がかかっているプログラムに対しては、GILの影響はそれほど出ないので、マルチスレッドに適している。
スレッド数とコア数を確かめるプログラム [3]:
import psutil
import os
import multiprocessing as mp
def ThreadNum():
nthreads = psutil.cpu_count(logical=True)
ncores = psutil.cpu_count(logical=False)
nthreads_per_core = nthreads // ncores
try:
nthread_available= len(os.sched_getaffinity(0))
except AttributeError:
nthread_available=mp.cpu_count()
ncores_available = nthreads_available // nthreads_per_core
print(f'{nthreads=}')
print(f'{ncores=}')
print(f'{nthreads_per_core=}')
print(f'{nthreads_available=}')
print(f'{ncores_available=}')
CuPy
CuPyはNumPyとSciPyで記述されたCPU用のプログラムをGPUで動かすためのツール.
簡単な移植作業により,GPUの高い計算性能を生かして高速に計算することができる.
CuPyのNumPyとの主な違いは以下の通り [4]。
- numpyをcupyに変える
- hostメモリーをdeviceメモリーを転送するには
cupy.array
関数を使用 (array
関数とasarray
関数は同じ) -
- deviceメモリーをhostメモリーに転送するには
cupy.asnumpy
関数を使用
- deviceメモリーをhostメモリーに転送するには
- CuPyではカーネル起動回数をなるべく少なくする
ベクトル及び行列計算における,NumPy, SciPy, CuPyの例は他にここを参照.
Numba for CUDA GPUs
- NVIDIA社のグラフィックスボード (GPU)を用いて高速に計算することができる
- C版のCUDAとほぼ同様のプログラムになる
- CuPy同様,カーネル起動回数をなるべく少なくする
Numba
jit化するもので,並列化を別のライブラリで行う (例えばこの例だとRay).
間違えやすいポイントがある[5]
2次元配列
2次元配列の計算方法には各種あり,方法によって計算時間に大きな差がでる.例えば,
- 配列演算
- プログラムが簡単になる
- 計算時間が短縮され,プロードキャストという技術を用いるとプログラムがより簡単になる
- Numba
- for文のままで高速化できる
- 配列演算と併用することもできる
cuDF
Pandasの強い版?
multiprocessing
並列処理を行うpythonの標準ライブラリ [6][7]
concurrent.future
Pythonの標準ライブラリで,
- ThreadPoolExecutor:スレッドベース
- ProcessPoolExecutor:プロセスベース
の2つがある [8].
Joblib
並列処理をはじめとする,以下の機能を提供.シンプルで簡単らしい [9][10].
- 並列化
- メモ化:計算結果を記録しておくことにより,重複する引数による関数の再計算を防ぎ,特に同じ引数が頻出する場面で高速化可能
- 直列化 (シリアライズ):大容量の計算結果を圧縮し,保存・取り出す
また,コード量が減り,
- 子プロセスで吐いたエラーも表示してくれる
- Ctrl+cで終了した時に子プロセスも終了してくれる
- 自動で全体の進捗を表示してくれるオプションがある
という利点もある [11].
ただし,クラスメソッドに適用すると,オーバーヘッドにより遅くなることが報告されている [12].
Ray
multiprocessingの代わりになってくれるよう.
分散並列処理をPythonicなコードで実現できる [13].
Tips
- 並列計算のオーバーヘッドにより計算効率が落ち,下位のnumpyのレベルでのマルチスレッド数を制限しておく必要があるときは,これをみる.ただし,Visual Studio Codeでの実行を想定しているよう.
まとめ?
- for文を書かない
- ライブラリを探す
- ドキュメントを読む
- NumPyが使えるときはNumPyを使い,NumPyが使えないときはNumbaを使用する
Refecences
[1] Pythonの並行処理を理解したい [マルチスレッド編]
[2] Pythonで並列処理のすすめ
[3] Python 並列化 Thred vs Process
[4] 高速化プログラミング入門 (Python版)
[5] Python を Numba で高速化するときの間違えやすいポイントまとめ
[6] pythonで並列化入門 (multiprocessing.Pool)
[7] multiprocessing
[8] Python concurrent.futureを用いた並列処理のさせ方メモ
[9] Joblibの様々な便利機能を把握する
[10] Python, Joblibでシンプルな並列処理(joblib.Parallel)
[11] [Python] Joblibでお手軽並列処理
[12] クラスメソッドをjoblibしたらかえって遅くなった話
[13] Pythonの分散並列処理ライブラリRayの使い方