一般に、スレッドを突然強制終了することは、悪いプログラミング方法であると考えられています。スレッドを突然強制終了すると、適切に閉じる必要がある重要なリソースが開いたままになる可能性があります。ただし、特定の時間が経過したり、割り込みが生成されたら、スレッドを強制終了したい場合があります。 Python でスレッドを強制終了するには、さまざまな方法があります。
- Python スレッドで例外を発生させる
- 停止フラグのセット/リセット
- トレースを使用してスレッドを強制終了する
- マルチプロセッシング モジュールを使用してスレッドを強制終了する
- Python スレッドをデーモンとして設定して強制終了する
- 隠し関数 _stop() の使用
Python スレッドで例外を発生させる:
このメソッドは関数を使用します PyThreadState_SetAsyncExc() スレッドで例外を発生させます。例えば、
Python3
# Python program raising> # exceptions in a python> # thread> import> threading> import> ctypes> import> time> > class> thread_with_exception(threading.Thread):> >def> __init__(>self>, name):> >threading.Thread.__init__(>self>)> >self>.name>=> name> > >def> run(>self>):> ># target function of the thread class> >try>:> >while> True>:> >print>(>'running '> +> self>.name)> >finally>:> >print>(>'ended'>)> > >def> get_id(>self>):> ># returns id of the respective thread> >if> hasattr>(>self>,>'_thread_id'>):> >return> self>._thread_id> >for> id>, thread>in> threading._active.items():> >if> thread>is> self>:> >return> id> > >def> raise_exception(>self>):> >thread_id>=> self>.get_id()> >res>=> ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,> >ctypes.py_object(SystemExit))> >if> res>>>1>:> >ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,>0>)> >print>(>'Exception raise failure'>)> > t1>=> thread_with_exception(>'Thread 1'>)> t1.start()> time.sleep(>2>)> t1.raise_exception()> t1.join()> |
>
>
上記のコードをマシンで実行すると、関数 raise_Exception() が呼び出されるとすぐに、ターゲット関数 run() が終了することがわかります。これは、例外が発生するとすぐにプログラム制御が try ブロックから飛び出し、run() 関数が終了するためです。その後、join() 関数を呼び出してスレッドを強制終了できます。 run_Exception() 関数が存在しない場合、ターゲット関数 run() は永久に実行され続け、スレッドを強制終了するために join() 関数が呼び出されることがありません。
停止フラグのセット/リセット:
スレッドを強制終了するには、停止フラグを宣言します。このフラグはスレッドによって時々チェックされます。例えば
Python3
# Python program showing> # how to kill threads> # using set/reset stop> # flag> import> threading> import> time> def> run():> >while> True>:> >print>(>'thread running'>)> >global> stop_threads> >if> stop_threads:> >break> stop_threads>=> False> t1>=> threading.Thread(target>=> run)> t1.start()> time.sleep(>1>)> stop_threads>=> True> t1.join()> print>(>'thread killed'>)> |
>
>
上記のコードでは、グローバル変数 stop_threads が設定されるとすぐにターゲット関数 run() が終了し、t1.join() を使用してスレッド t1 を強制終了できます。ただし、何らかの理由によりグローバル変数の使用を控える場合があります。このような状況では、以下に示すように、関数オブジェクトを渡して同様の機能を提供できます。
Python3
# Python program killing> # threads using stop> # flag> import> threading> import> time> def> run(stop):> >while> True>:> >print>(>'thread running'>)> >if> stop():> >break> > def> main():> >stop_threads>=> False> >t1>=> threading.Thread(target>=> run, args>=>(>lambda> : stop_threads, ))> >t1.start()> >time.sleep(>1>)> >stop_threads>=> True> >t1.join()> >print>(>'thread killed'>)> main()> |
>
>
上記のコードで渡された関数オブジェクトは、常にローカル変数 stop_threads の値を返します。この値は関数 run() でチェックされ、stop_threads がリセットされるとすぐに run() 関数が終了し、スレッドを強制終了できます。
トレースを使用してスレッドを強制終了する:
この方法はインストールすることで機能します 痕跡 各スレッドで。各トレースは何らかの刺激やフラグが検出されると自動的に終了し、関連するスレッドが即座に強制終了されます。例えば
Python3
# Python program using> # traces to kill threads> import> sys> import> trace> import> threading> import> time> class> thread_with_trace(threading.Thread):> >def> __init__(>self>,>*>args,>*>*>keywords):> >threading.Thread.__init__(>self>,>*>args,>*>*>keywords)> >self>.killed>=> False> >def> start(>self>):> >self>.__run_backup>=> self>.run> >self>.run>=> self>.__run> >threading.Thread.start(>self>)> >def> __run(>self>):> >sys.settrace(>self>.globaltrace)> >self>.__run_backup()> >self>.run>=> self>.__run_backup> >def> globaltrace(>self>, frame, event, arg):> >if> event>=>=> 'call'>:> >return> self>.localtrace> >else>:> >return> None> >def> localtrace(>self>, frame, event, arg):> >if> self>.killed:> >if> event>=>=> 'line'>:> >raise> SystemExit()> >return> self>.localtrace> >def> kill(>self>):> >self>.killed>=> True> def> func():> >while> True>:> >print>(>'thread running'>)> t1>=> thread_with_trace(target>=> func)> t1.start()> time.sleep(>2>)> t1.kill()> t1.join()> if> not> t1.isAlive():> >print>(>'thread killed'>)> |
>
>
このコードでは、start() がわずかに変更され、次を使用してシステム トレース関数を設定します。 セットトレース() 。ローカル トレース関数は、それぞれのスレッドの kill フラグ (killed) が設定されるたびに、次のコード行の実行時に SystemExit 例外が発生し、ターゲット関数 func の実行が終了するように定義されています。これで、join() を使用してスレッドを強制終了できるようになりました。
マルチプロセッシング モジュールを使用してスレッドを強制終了する:
Python のマルチプロセッシング モジュールを使用すると、スレッド モジュールを使用してスレッドを生成するのと同じ方法でプロセスを生成できます。マルチスレッド モジュールのインターフェイスは、スレッド モジュールのインターフェイスと似ています。たとえば、特定のコードで、1 から 9 までカウントされる 3 つのスレッド (プロセス) を作成しました。
Python3
# Python program creating> # three threads> import> threading> import> time> # counts from 1 to 9> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Thread '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> # creates 3 threads> for> i>in> range>(>0>,>3>):> >thread>=> threading.Thread(target>=>func, args>=>(i,))> >thread.start()> |
>
>
上記のコードの機能は、ほとんど変更を加えずに、同様の方法でマルチプロセッシング モジュールを使用して実装することもできます。以下のコードを参照してください。
Python3
# Python program creating> # thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Processing '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> for> i>in> range>(>0>,>3>):> >process>=> multiprocessing.Process(target>=>func, args>=>(i,))> >process.start()> |
>
>
Javaを印刷する方法
2 つのモジュールのインターフェイスは似ていますが、実装は大きく異なります。すべてのスレッドはグローバル変数を共有しますが、プロセスは互いに完全に分離されています。したがって、プロセスを強制終了することは、スレッドを強制終了するよりもはるかに安全です。 Process クラスにはメソッドが提供されます。 終了() 、プロセスを強制終了します。さて、最初の問題に戻ります。上記のコードで、0.03 秒が経過した後にすべてのプロセスを強制終了したいとします。この機能は、次のコードのマルチプロセッシング モジュールを使用して実現されます。
Python3
# Python program killing> # a thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Processing '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> # list of all processes, so that they can be killed afterwards> all_processes>=> []> for> i>in> range>(>0>,>3>):> >process>=> multiprocessing.Process(target>=>func, args>=>(i,))> >process.start()> >all_processes.append(process)> # kill all processes after 0.03s> time.sleep(>0.03>)> for> process>in> all_processes:> >process.terminate()> |
>
>
ただし、2 つのモジュールの実装は異なります。上記のコードのマルチプロセッシング モジュールによって提供されるこの機能は、スレッドを強制終了することに似ています。したがって、マルチプロセッシング モジュールは単純なモジュールとして使用できます。 代替 Python でスレッドの強制終了を実装する必要があるときはいつでも。
デーモンとして設定して Python スレッドを強制終了します。
デーモンスレッド メインプログラムが終了するときに強制終了されるスレッドです。例えば
Python3
import> threading> import> time> import> sys> def> func():> >while> True>:> >time.sleep(>0.5>)> >print>(>'Thread alive, and it won't die on program termination'>)> t1>=> threading.Thread(target>=>func)> t1.start()> time.sleep(>2>)> sys.exit()> |
>
>
スレッド t1 は生き続けており、メイン プログラムが sys.exit() によって終了するのを妨げていることに注意してください。 Python では、生きている非デーモン スレッドはメイン プログラムの終了をブロックします。一方、デーモン スレッド自体は、メイン プログラムが終了するとすぐに強制終了されます。つまり、メイン プログラムが終了すると、すべてのデーモン スレッドが強制終了されます。スレッドをデーモンとして宣言するには、キーワード引数 daemon を True に設定します。たとえば、指定されたコードでは、デーモン スレッドのプロパティを示しています。
Python3
# Python program killing> # thread using daemon> import> threading> import> time> import> sys> def> func():> >while> True>:> >time.sleep(>0.5>)> >print>(>'Thread alive, but it will die on program termination'>)> t1>=> threading.Thread(target>=>func)> t1.daemon>=> True> t1.start()> time.sleep(>2>)> sys.exit()> |
>
>
メイン プログラムが終了するとすぐに、スレッド t1 が強制終了されることに注意してください。この方法は、プログラムの終了を使用してスレッドの強制終了をトリガーできる場合に非常に役立つことがわかります。 Python では、生きているデーモン スレッドの数に関係なく、デーモン以外のスレッドがすべてなくなるとすぐにメイン プログラムが終了することに注意してください。したがって、これらのデーモン スレッドによって保持されている、開いているファイルやデータベース トランザクションなどのリソースが適切に解放されない可能性があります。 Python プログラムの制御の最初のスレッドはデーモン スレッドではありません。スレッドを強制的に強制終了することは、リークやデッドロックが発生しないことが確実にわかっている場合を除き、推奨されません。
隠し関数 _stop() を使用する:
スレッドを強制終了するには、隠し関数 _stop() を使用します。この関数は文書化されていませんが、Python の次のバージョンでは消える可能性があります。
Python3
# Python program killing> # a thread using ._stop()> # function> import> time> import> threading> class> MyThread(threading.Thread):> ># Thread class with a _stop() method.> ># The thread itself has to check> ># regularly for the stopped() condition.> >def> __init__(>self>,>*>args,>*>*>kwargs):> >super>(MyThread,>self>).__init__(>*>args,>*>*>kwargs)> >self>._stop>=> threading.Event()> ># function using _stop function> >def> stop(>self>):> >self>._stop.>set>()> >def> stopped(>self>):> >return> self>._stop.isSet()> >def> run(>self>):> >while> True>:> >if> self>.stopped():> >return> >print>(>'Hello, world!'>)> >time.sleep(>1>)> t1>=> MyThread()> t1.start()> time.sleep(>5>)> t1.stop()> t1.join()> |
>
>
注記: Python にはスレッドを強制終了する直接的な方法が用意されていないため、上記の方法は状況によっては機能しない可能性があります。