aoishiの備忘録

備忘録

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モジュールで簡単にプロセス名を変更できました。

参考

qiita.com