背景
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 コードの開発がはかどりますね!