pythonでmultiprocessingの使い方を調査しています。
先ほど投稿した記事の調査の続き。別プロセスで動かしたい関数をProcess で一つ一つ起動するのでなく、まとめて実行してくれる関数Pool を利用します。
- 並列処理で使用するコアの数(上限数)を指定できる。
- 指定した処理を別コアで動かしてくれる。感じ。
- 並列処理をしたい関数が同じで引数が違うだけの時、Pool を使って簡単に書ける。
を確認しました。
テストコード
- CPUの数は
cpu_count()
で取得できる -
Pool(num_cpu)
で Pool のインスタンスを作り、```map(method, iterable_arg)``
from multiprocessing import Pool, cpu_count
from time import sleep
from os import getpid, getppid
from numpy import exp, log
def f(args):
print("[{}---{}] args {}".format(getpid(), getppid(), args))
if isinstance(args, dict):
y = args["x"]
elif isinstance(args, int):
y = args
retValue =0.0
try:
sleep(1)
for i in range(1000000):
retValue = retValue/float(i+1) + log(exp(y * y + 1) - 0.1)
print("here=", 100/0.0)
except Exception as e:
print("[{}---{}] {}".format(getpid(), getppid(), e))
raise e
finally:
print('[{}---{}] return: {}'.format(getpid(), getppid(), retValue))
return(retValue)
if __name__ == "__main__":
print("main pid={} cpu_count={}".format(getpid(), cpu_count()))
p = Pool(6) # プロセス数を指定する
try:
result = p.map(f, [{"x":1}, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]) # リストで引数を指定する
print(result)
except Exception as e:
print("main", e)
実行結果
ちゃんとCPUを分けて使ってくれています。8コアのPCですが、Pool(10)
としてもエラーは出ません。8個すべてを使って全力で処理してくれているようです。
他に気が付いたこと。基礎知識が無いので実験的に学んでいます。汗;
- プロセスIDは再利用されている。(ので、関数の実行のunique な識別には利用できませんね。)
- 発生したException は親プロセスではキャッチされない。(そりゃそうか)
-
map
で実行させる関数の引数は、型が違ってもOK。map はIterable なもので、実行させる関数できちんと処理をしていれば。
またCPU数については、ドキュメントには
multiprocessing.cpu_count()
については、APIの説明で
This number is not equivalent to the number of CPUs the current process can use. The number of usable CPUs can be obtained with len(os.sched_getaffinity(0))
と書かれていましたが、私が実行したときは、os.sched_getaffinity(0)
はいつも {0, 1, 2, 3, 4, 5, 6, 7}
でした。CPUの割り当て方とか何か実装方法があるのかな。
参考にさせていただいた情報
-
実は記事の一番最初にPool の使い方を紹介されている。https://docs.python.org/3/library/multiprocessing.html
-
実際に使うときの不都合等についての情報も。https://qiita.com/yukitaka13-1110/items/2580b4fc6c8a30d34661
-
並列処理 https://qiita.com/studio_haneya/items/1cf192a0185e12c7559b
-
こちらではmultiprocessing.py のソースコードを読まれていました。https://qiita.com/bananaumai/items/48ee1b4b069a5c17bc6f
来週、何とかなるといいな。
(2020/04/18)
追記(2020/04/18 17:40)
- よく読むと、Pool を使うときは
with Pool(processes=4) as pool:
としたほうが良いみたい。with を抜けるときにPool のprocessが close されるみたい。