2016-09-02 8 views
1

私はWindowsでPython 3.5.2を使用しています。Pythonの子スレッド内から親スレッドを強制終了できますか?

私はPythonスクリプトを実行したいですが、N秒を超えないようにします。 の場合、N秒を超えると例外が発生し、プログラムを終了する必要があります。最初は、例外をスローする前にN秒待つスレッドを最初に起動できると考えましたが、これは親スレッドではなくタイマースレッドに例外をスローすることのみを管理します。

import threading 
import time 

def may_take_a_long_time(name, wait_time): 
    print("{} started...".format(name)) 
    time.sleep(wait_time) 
    print("{} finished!.".format(name)) 

def kill(): 
    time.sleep(3) 
    raise TimeoutError("No more time!") 

kill_thread = threading.Thread(target=kill) 
kill_thread.start() 

may_take_a_long_time("A", 2) 
may_take_a_long_time("B", 2) 
may_take_a_long_time("C", 2) 
may_take_a_long_time("D", 2) 

この出力:たとえば

A started... 
A finished!. 
B started... 
Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner 
    self.run() 
    File "C:\Program Files\Python35\lib\threading.py", line 862, in run 
    self._target(*self._args, **self._kwargs) 
    File "timeout.py", line 11, in kill 
    raise TimeoutError("No more time!") 
    TimeoutError: No more time! 

B finished!. 
C started... 
C finished!. 
D started... 
D finished!. 

これはリモートで可能であってもですか?私はこのような何かを行うことができ実現:

import threading 
import time 

def may_take_a_long_time(name, wait_time, thread): 
    if not thread.is_alive(): 
     return 
    print("{} started...".format(name)) 
    time.sleep(wait_time) 
    print("{} finished!.".format(name)) 

def kill(): 
    time.sleep(3) 
    raise TimeoutError("No more time!") 

kill_thread = threading.Thread(target=kill) 
kill_thread.start() 

may_take_a_long_time("A", 2, kill_thread) 
may_take_a_long_time("B", 2, kill_thread) 
may_take_a_long_time("C", 2, kill_thread) 
may_take_a_long_time("D", 2, kill_thread) 

しかし、この方法は、例えば、may_take_a_long_time("B", 60, kill_thread)が呼び出された、失敗します。

私のTL; DRの質問は、メインスレッド自体に時間制限を設ける最良の方法は何ですか?

+0

を。そのためのAPIはありません。あなたのコードで何をしているのかは、新しいスレッド_の中で例外を発生させているだけで、主なスレッドには影響しません。 – ForceBru

+0

期限の目的は何ですか?一定の時間以上何かが起きるのを待たずに待っていれば、待っているだけです。 –

+0

@ForceBru私はそれが主要なものに影響しないことを知っています、それは私の問題です。これは私の最初の素朴な実装でした。私は一連の関数( 'may_take_a_long_time')が** N **秒を超えないようにする方法を見つけようとしています。 – DJMcMayhem

答えて

3

あなたは_thread.interrupt_main(このモジュールはPython 2.7でthreadと呼ばれている)を使用することができます:あなたはすべてのPythonのスレッドを_kill_することはできません

import time, threading, _thread 

def long_running(): 
    while True: 
     print('Hello') 

def stopper(sec): 
    time.sleep(sec) 
    print('Exiting...') 
    _thread.interrupt_main() 

threading.Thread(target = stopper, args = (2,)).start() 

long_running() 
+0

おかげで!それはまさに私が探していたものです(そして速くも!)。どのような例外がスローされるのかを変更できるかどうか知っていますか? 'KeyboardInterrupt'は私がやっていることとはあまり関係がないようです。 – DJMcMayhem

+0

@DJMcMayhem、ドキュメントによると、この関数は 'KeyboardInterrupt'sだけをスローします。実際には、例外が「ストッパー」によって生成され、このケースを別の方法で処理することを示すグローバル変数を含むトリッキーを含むことができます。しかし、メインスレッドで例外をキャッチした場合、長時間実行されている関数は終了し、その結果は失われます。そのため、その関数自体の中で_処理することができます。 – ForceBru

2

親スレッドがルートスレッドの場合は、os._exit(0)を試してみるとよいでしょう。

import os 
import threading 
import time 

def may_take_a_long_time(name, wait_time): 
    print("{} started...".format(name)) 
    time.sleep(wait_time) 
    print("{} finished!.".format(name)) 

def kill(): 
    time.sleep(3) 
    os._exit(0) 

kill_thread = threading.Thread(target=kill) 
kill_thread.start() 

may_take_a_long_time("A", 2) 
may_take_a_long_time("B", 2) 
may_take_a_long_time("C", 2) 
may_take_a_long_time("D", 2) 
+1

残念ながら、それは動作しません。私は、 'sys.exit()'は親スレッドの振る舞いを変更することなく、どのスレッドから呼び出されたものであっても制限されていると推測しています。 – DJMcMayhem

+0

'os._exit(n)'は正しいものです。 – rbanffy

+0

これはもっとうまく動作しますが、実際には例外を発生させたりエラーを投げたりすることはないので、おそらくそれを使用することはまずありません。 – DJMcMayhem

関連する問題