LoginSignup
0
0

Speeding up Python

Last updated at Posted at 2024-04-04

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関数を使用
  • 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の使い方

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0