LoginSignup
4
1

More than 3 years have passed since last update.

Python スクリプトを自動再起動するメモ

Last updated at Posted at 2021-01-29

背景

numpy + C/C++ native module のある python コードでスクリプト自動リロードをやって開発効率を高めたい.
(native module の import はリロード対応していないため)

yarr で Python で numpy データをさくっと RPC 通信するメモ
https://qiita.com/syoyo/items/c393d1a6d596c7f7f30f

の続きです.

プロセスの自動起動は pm2 など使う手もありそうですが, いろいろセットアップがめんどいのでとりあえずは bash スクリプトで起動しなおしというふうにします.

方法

# server.py
import sys
import yarr
import numpy

import socketserver

def proc_numpy(a):
    print(a)

def quit(retcode: int):
    sys.exit(retcode)

# server
socketserver.TCPServer.allow_reuse_address = True
yarr.yarr(('localhost', 8000), [proc_numpy, quit])

yarr は内部で socketserver を使っています.
allow_reuse_address を有効にしておかないと, カーネル側でソケットの情報がしばらく(5~10 秒くらい?)残るため, 再起動すると socket address already used エラーになります. これを解決します(もしくは quit するときに socket の close() を明示的に行うか)

プロセス自動起動

プロセス自動起動ツールとかはぱぱっと使えるいいのが探してもありません
(悪用しやすいからですかね)

とりあえず簡単な bash スクリプトで対応する場合.

#!/bin/bash

while true; do

  echo "start server..."

  python server.py

  echo "retcode " $?

  sleep 1

  echo "restart server..."

done
# client.py
import yarr
import numpy

a = numpy.random.rand(256, 512, 512)

yarr.call(('localhost', 8000), 'proc_numpy', a)

# load() error in yarr will happen when exiting a server, so catch it as a work around.
try:
    yarr.call(('localhost', 8000), 'quit', int(1))
except Exception as e:
    pass

呼び出す側です. yarr.call では, RPC 発行のあといくつか後処理で相手と通信していますが, quit を呼ぶと相手はプロセス終了しておりエラーが発生してしまいます.
とりあえずは try/except で suppress します.

これで自動でプロセスが再起動するようになりました!

python 自身で再起動

ありがとうございます. os.execv で行けました.
自己実行形式にしていない場合は, `

にあるように os.execv(sys.executable, ['python'] + sys.argv) にします.

自己再実行の場合の server は以下のようになります.

import sys
import yarr
import numpy
import os

import socketserver

def proc_numpy(a):
    print(a)

def quit(retcode: int):
    print("restarting... ")
    # Restart python script itself
    os.execv(sys.executable, ['python'] + sys.argv)

# server
print("server start")
socketserver.TCPServer.allow_reuse_address = True
yarr.yarr(('localhost', 8000), [proc_numpy, quit])

これで server 側の起動は普通に

$ python server.py

で起動するだけです! あとは quit コマンドを受け取ったら自分でよろしく再起動してくれます!

特に RPC で分けるほどではないスクリプトの場合(e.g. データロードなど前処理の量が多くない, jupyter-lab など使わずにコマンドラインで実行している)は, os.execv であれば単体スクリプトのままで使えますね.

watchdog と組み合わせ live reload っぽいことをする

ファイルの変更などを watch してくれる watchdog と組み合わせれば,
自前スクリプトをエディタなどで書き換えたときに os.execv 呼んで再起動し live reload 相当というのもできます!

ファイルの更新をきっかけにコマンド実行 (python編)
https://qiita.com/ksato9700/items/ea4b769d010e8cf1fb0c

ありがとうございます.

まとめ

C/C++ native module 含んだ python コードの開発がはかどりますね!

4
1
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
4
1