2016-12-01 6 views
0

Pythonで一定時間後に(まだ実行中の)関数を強制終了する最も良い方法はありますか?これが私たちの基本機能であると言う与えられた時間が経過した後にPython関数を終了する

import time 
def foo(): 
    a_long_time = 10000000 
    time.sleep(a_long_time) 

TIMEOUT = 5 # seconds 

1.マルチプロセッシングアプローチ

import multiprocessing 

if __name__ == '__main__': 
    p = multiprocessing.Process(target=foo, name="Foo") 
    p.start() 

    p.join(TIMEOUT) 

    if p.is_alive() 
     print('function terminated') 
     p.terminate() 
     p.join() 

2.シグナル・アプローチ

これらは私がこれまでに発見した二つのアプローチです
import signal 

class TimeoutException(Exception): 
    pass 

def timeout_handler(signum, frame): 
    raise TimeoutException 

signal.signal(signal.SIGALRM, timeout_handler) 


signal.alarm(TIMEOUT)  
try: 
    foo() 
except TimeoutException: 
    print('function terminated') 

これらの2つの方法の範囲、安全性、使いやすさの面でのメリットとデメリットは何ですか?より良いアプローチはありますか?

答えて

1

いつものように、それは依存しています。

すでに確認済みですので、これらの両方の方法が機能します。私はそれがあなたのアプリケーションと正しい実装に依存していると言います(あなたのシグナリング方法は少し間違っています...)

どちらの方法も正しく実装されていると "安全"と考えることができます。これは、foo関数の外部にあるメインプログラムが何かをする必要があるかどうか、あるいはfooが完了するかタイムアウトするまで待つことができるかによって異なります。シグナリング方法は、あなたのメインプログラムが完了するかタイムアウトするまで、foo()にあるので、並列処理を許可しません。しかし、信号を解消する必要があります。あなたのfooが1秒で完了すると、あなたのメインプログラムはtry/except構造を離れ、4秒後に... kaboom ...例外が発生し、おそらくキャッチされません。良くない。

try: 
    foo() 
    signal.alarm(0) 
except TimeoutException: 
    print ("function terminated") 

が問題を解決します。

私は個人的にはマルチプロセッシングのアプローチを好みます。プログラムの実行が信号が発生したときの位置ではないと理論的に間違える可能性がある、シグナルと例外処理は不要です。あなたのプログラムがjoin()で待っていれば、完了です。しかし、あなたが待っている間にメインプロセスで何かしたいのであれば、ループに入り、変数の時間を追跡し、タイムアウトが過ぎていないかどうかをチェックし、そうであればプロセスを終了することができます。プロセスがまだ実行中の場合は、わずかなタイムアウトでjoinを使用して "peek"を使用します。

foo()に依存するもう1つの方法は、クラスまたはグローバル変数でスレッドを使用することです。あなたのfooは、処理コマンドの代わりに、おそらく最後までコマンドのために長い時間を待って、あなたがそこにif節を追加することができます続けた場合:do_stuffとdo_more_stuff完全な場合は妥当な時間内に

def foo(): 
    global please_exit_now 
    while True: 
     do_stuff 
     do_more_stuff 
     if foo_is_ready: 
      break 
     if please_exit_now is True: 
      please_exit_now = False 
      return 
    finalise_foo 
    return 

を、あなたがしてできましたあなたのメインプログラム内のものを処理し、グローバルなplease_exit_nowをTrueに設定すると、あなたのスレッドは最終的にそれに気付き、終了します。

多分、私はあなたのマルチプロセッシングと参加に行くでしょう。

ハヌー

+0

キャッチオン信号アプローチに感謝します。私は並列処理とシンプルさのためにマルチプロセッシングの使用を計画していると思います。 – Anna

+1

マルチプロセッシングでは、try/exceptを使用してp.terminate()をカプセル化してください。アプリケーションが頻繁に使用されると、p.join()のタイムアウトがpのままで、p.is_alive()がtrueを返し、pが直後に終了し、p.terminate()を呼び出すと、 pがもう動いていないので例外が発生します。あなたのアプリケーションの状態があなたが望むもの(実行中ではない)であるので、例外を簡単に無視することができますが、キャッチされなければメインプログラムはこの時点で終了します。 – Hannu

+0

実際には、is_alive()チェックは、is_aliveと次のコマンドの間でpが死ぬ可能性があるため、追加の有用な情報を提供しないので、まったく必要ありません。 try/exceptの中でp.terminate()を呼び出し、例外を無視するだけです。それは成功するか失敗するかにかかわらず、あなたのpは消えます。 – Hannu

関連する問題