Pythonのsetproctitleモジュールでプロセス名を設定する
Pythonのmultiprocessingモジュールで書かれたマルチプロセスなプログラムで、psコマンドで親・子プロセス名を分かりやすく表示させるために、setproctitleモジュールを使ってプロセス名を設定してみました。
環境
multiprocessingモジュールを使ったマルチプロセスなプログラム
下記は、単にsleepする子プロセスを2つ作成してデーモン化するプログラムです。
試しにp1というプロセスにのみname引数を渡しています。マニュアルによるとプロセスの名前と記載されていますが、psコマンドで確認するとどうなるでしょうか。
17.2. multiprocessing — プロセスベースの並列処理 — Python 3.6.3 ドキュメント
from multiprocessing import Process import time def child_process(): while True: time.sleep(1) def main(): try: p1 = Process(target=child_process, name='child process 1') p1.daemon = True p1.start() p2 = Process(target=child_process) p2.daemon = True p2.start() while True: time.sleep(1) except: p1.terminate() p2.terminate() if __name__ == '__main__': main()
下記が、上記プログラムを実行してpsコマンドでプロセス名を確認してみた結果です。
$ python test_setproctitle_1.py ※ 下記の別ターミナルでのプロセス確認が完了したらctrl-cで終了する 別のターミナルでプロセス名を確認 $ ps -ef UID PID PPID C STIME TTY TIME CMD ~~~~~ aoishi 31489 9574 2 02:16 pts/2 00:00:00 python test_setproctitle_1.py aoishi 31513 31489 0 02:16 pts/2 00:00:00 python test_setproctitle_1.py aoishi 31514 31489 0 02:16 pts/2 00:00:00 python test_setproctitle_1.py
親・子プロセスともにプログラムの実行コマンドがプロセス名として表示されています。name 引数の内容はpsコマンドのプロセス名には反映されないようです。
setproctitleモジュールでプロセス名を変更
setproctitleモジュールをインストールしておきます。
$ pip install setproctitle
先ほどのプログラムに対して、setproctitleモジュールを使ってプロセス名を設定してみたのが下記になります。
import setproctitle from multiprocessing import Process, current_process import time def child_process(): setproctitle.setproctitle(current_process().name) while True: time.sleep(1) def main(): setproctitle.setproctitle('parent process') try: p1 = Process(target=child_process, name='child process 1') p1.daemon = True p1.start() p2 = Process(target=child_process) p2.daemon = True p2.start() while True: time.sleep(1) except: p1.terminate() p2.terminate() if __name__ == '__main__': main()
変更点は下記になります。
- setproctitleモジュールをimportした
- multiprocessingモジュールからcurrent_processメソッドをimportした(child_process内で自身のProcessオブジェクトを参照するため)
- child_processメソッド内で、setproctitle.setproctitleメソッドを使って子プロセス名をname引数で渡された文字列に設定した
- mainメソッド内で、setproctitle.setproctitleメソッドを使って親プロセス名を設定した
下記が、先ほどと同じように実行して確認した結果です。
$ python test_setproctitle_2.py ※ 下記の別ターミナルでのプロセス確認が完了したらctrl-cで終了する 別のターミナルでプロセス名を確認 $ ps -ef UID PID PPID C STIME TTY TIME CMD ~~~~~ aoishi 31633 9574 2 02:16 pts/2 00:00:00 parent process aoishi 31657 31633 0 02:16 pts/2 00:00:00 child process 1 aoishi 31658 31633 0 02:16 pts/2 00:00:00 Process-2
今度はプロセス名が親・子プロセスとで変わっています。プロセス名を明示的に指定していないp2プロセスについてはプロセス名が Process-2 となっていますが、下記ドキュメントにも記載されているように、name引数を指定しなかった場合の仕様のようです。
https://docs.python.jp/3/library/multiprocessing.html#multiprocessing.Process.name
子プロセスは親プロセス名を引き継ぐ
おまけ的な内容になりますが、子プロセスは親プロセスのプロセス名を引き継ぐようです。 子プロセス側で変更していなければ、コピーオンライトで親プロセスとページ共有されるので、よくよく考えたら同じであっても全く不思議ではないですね。。。
確認のために、親プロセスだけsetproctitleモジュールでプロセス名を設定するようにしてみました。
import setproctitle from multiprocessing import Process, current_process import time def child_process(): while True: time.sleep(1) def main(): setproctitle.setproctitle('parent process') try: p1 = Process(target=child_process, name='child process 1') p1.daemon = True p1.start() p2 = Process(target=child_process) p2.daemon = True p2.start() while True: time.sleep(1) except: p1.terminate() p2.terminate() if __name__ == '__main__': main()
これまでと同じように実行してみます。
$ python test_setproctitle_3.py ※ 下記の別ターミナルでのプロセス確認が完了したらctrl-cで終了する 別のターミナルでプロセス名を確認 $ ps -ef UID PID PPID C STIME TTY TIME CMD ~~~~~ aoishi 3328 9574 2 02:49 pts/2 00:00:00 parent process aoishi 3329 3328 0 02:49 pts/2 00:00:00 parent process aoishi 3330 3328 0 02:49 pts/2 00:00:00 parent process
2つの子プロセスともに、親プロセスで指定したプロセス名になっています。
まとめ
setproctitleモジュールで簡単にプロセス名を変更できました。