Pythonで制限時間を設けてプログラムを処理(fork & signalを使って ) | 世界的日曜WEBプログラマー日記

世界的日曜WEBプログラマー日記

一年後に世界的なWEBサービスを運営するにはどうすればいいのか書いていく(予定)

プロセス系のPythonスクリプトを書いていると、あるプログラムが指定時間以上経過したら即座にプログラムをエラーとみなして終了したい、という処理をしたい時がある。
例えばSeleniumとかでWebチェックをする時、ほっておくといつまでたっても返事がかえってこない。そのため時間制限をもうけて、時間以内は正常、それ以外は異常など処理したい時など。
お弁当宅配サイトのマイ食の自動テストサービスを作っているときにこの必要性があった)

ここではフォークして、今の仕事を子供プロセスに任せる。親プロセスは子プロセスを指定時間までまち、指定時間経過後もまだ子供プロセスが生きていたら殺す。というプログラムの例を載せる。
signal, os, sysなどを使う。
本当はThreadingを使ってSignalをやりとりでいいじゃないか!という人もいるかもしれないけれど今回はそうしなかった。感覚的にThreadingでSignalをやり取りするのはなんかマズイ気がするが…。

とにかく今回はForkで。。

import time, os, sys, signal

def mysleep( secs ):
time.sleep( secs )

def doit( limit_waiting_time, function, **args ):
child_id = os.fork()
if child_id != 0: # Parent process
# Waiting for child process to do some works
time.sleep( limit_waiting_time )
# Seach child process whther the process is workinng.
commands = os.popen( 'ps aux | grep %d | grep -v grep' % child_id )
lines = commands.readlines()
# There is no line or Zonbi process in the line, then the child was dead. ( OK )
if len( lines ) == 0 or 'Z+' in lines[ 0 ].strip():
CAN_KILLED=True
else: # The child process is still working( not killed, not good )
os.kill( child_id, signal.SIGKILL ) # kill it.
CAN_KILLED=False


if CAN_KILLED:
return True
else:
return False

else: # !! Child process !!
function( **args ) # doit something as child.
sys.exit() # <= not to write os._exit

def main():
print doit( 3, mysleep, secs = 5.0 )

if __name__ == '__main__':
main()


関数のmysleepはサンプルのために作った適当な関数。この部分を独自の関数にすればいい。
doitがメインの関数となっている。(名前に問題あるかもしれないけど、今はこれでいいかなと)

株式会社OctOpt
コンピューターサイエンス会社OctOptの技術公式ブログ
等々力 康弘
@rocky_house