まえがき(ちゅうい)
当方並列、非同期に詳しくないです
マサカリはコメントにて随時お待ちしています
ドキュメントに書いてあるようなレベルの低レベルなお話です
TL;DR
PyInstallerにmultiprocessingを使うときは
必ずmultiprocessing.freeze_support()を最初に呼ぶようにする
無駄な本文
multiprocessing
Pythonで並列しようと思ったら標準にthreading, multiprocessing, asyncioがあります
全部挙動に違いがあるらしいのでその辺は調べてください
今回はmultiprocessingについてです
import multiprocessing as mp
import time
def f(x):
time.sleep(1)
return x
def main():
with mp.Pool(processes=3) as p:
r = p.imap(f, [1, 2, 3])
result = list(r)
print(result)
if __name__ == '__main__':
main()
例えば上のようなコードを書いてやると
$python hoge.py
[1, 2, 3]
みたいな出力が約1秒後に出ます
1秒待たされる関数fを3つプロセス生成して3つ同時に動くようにしたわけです
def main():
result = []
for i in [1, 2, 3]:
result.append(f(i))
print(result)
みたいな下手を打つと3秒かかっちゃうので3倍速です
嬉しいですね
PyInstaller
PyInstallerはpyファイルから実行ファイルを吐いてくれます
ただし動かしてるOS用のものが吐かれるのでそこは注意
linux上ではlinux用の実行ファイルが、Windows上ではexeが吐かれます
実行もお手軽で、
$pyinstaller hoge.py
みたいにしてやるといい具合にやってくれます
ひとまとめにしてやりたいときは--onefile
オプションつけるだけ
簡単ですね
本題
では上のhoge.py
を実際にPyInstallerにかけて、吐かれた実行ファイルを実行したりするとどうなるかというと、
- Linux: 実行できる
- Windows: 実行できない(挙動は様々ですが大量のタスクが生成されてCPUに異常な負荷がかかったりします)
というわけでWindowsユーザーが悲しみを背負います
multiprocessing.freeze_support()
そこでこいつを使います
どうやらWindowsでは上手くいかないのに対応するためだけに存在するようなものらしく、書かれていてもLinux上では影響はありません
というわけで
import multiprocessing as mp
import time
def f(x):
time.sleep(1)
return x
def main():
with mp.Pool(processes=3) as p:
r = p.imap(f, [1, 2, 3])
result = list(r)
print(result)
if __name__ == '__main__':
mp.freeze_support() #add this line
main()
この1行足すだけでexeも普通に動きます
けつろん
- PyInstallerなどで実行ファイルを作りたい時
- Windows上での実行ファイルの利用がある時
はmultiprocessing.freeze_support()
をとりあえず最初に書いておきましょう
参考
https://docs.python.org/ja/3/library/multiprocessing.html
公式ドキュメントは正義