Python でスレッドを終了する方法: 1. stop 関数を呼び出し、join 関数を使用してスレッドが適切に終了するのを待ちます; 2. Python スレッドで例外を発生させます; 3. 「thread. join" を実行してスレッドを終了します。
この記事の動作環境: Windows 7 システム、Python バージョン 3.5、DELL G3 コンピューター。
Python でスレッドを終了するには、set/check--->フラグまたはロックを行うのが従来の方法であることはわかっています。
この方法は良いですか?
あまり良くないはずです。なぜなら、すべてのプログラミング言語において、スレッドを突然終了することは、いかなる場合でも良い設計パターンではないからです。
同時に
#次のような状況はさらに悪化する場合もあります。なぜスレッドには開始だけがあって終了がないのかご存知ですか?
ご存知のとおり、スレッドは通常、ネットワーク接続、システム リソースの解放、ストリーミング ファイルのダンプに使用されます。これらはすべて IO に関連しています。スレッドを突然閉じた場合、次のような場合はどうすればよいですかが正しく閉じられていませんか?自分のためにバグを作っているだけですか?ああ? !
したがって、この種のことで最も重要なことは、スレッドを終了することではなく、解決策 · 一より良い方法は、各スレッドに終了要求フラグを設定し、スレッド内で一定の間隔でチェックして、自分で終了する必要があるかどうかを確認することです。 !スレッドをクリーンアップすることです。
import threading class StoppableThread(threading.Thread): """Thread class with a stop() method. The thread itself has to check regularly for the stopped() condition.""" def __init__(self): super(StoppableThread, self).__init__() self._stop_event = threading.Event() def stop(self): self._stop_event.set() def stopped(self): return self._stop_event.is_set()コードのこの部分に示すように、スレッドを終了する場合は、明示的に stop() 関数を呼び出し、join() 関数を使用してスレッド
が終了するのを待つ必要があります。 適切に。スレッドは定期的に停止フラグをチェックする必要があります。
ただし、実際にスレッドを強制終了する必要がある使用シナリオもいくつかあります。たとえば、外部ライブラリをカプセル化するが、外部ライブラリが長時間 を呼び出す場合などです。このプロセスを中断したい。
[推奨:python ビデオ チュートリアル ]
解決策 · 2次の解決策は、Python スレッドで例外を発生できるようにすることです (もちろん、一部制限があります)。def _async_raise(tid, exctype): '''Raises an exception in the threads with id tid''' if not inspect.isclass(exctype): raise TypeError("Only types can be raised (not instances)") res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: # "if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) raise SystemError("PyThreadState_SetAsyncExc failed") class ThreadWithExc(threading.Thread): '''A thread class that supports raising exception in the thread from another thread. ''' def _get_my_tid(self): """determines this (self's) thread id CAREFUL : this function is executed in the context of the caller thread, to get the identity of the thread represented by this instance. """ if not self.isAlive(): raise threading.ThreadError("the thread is not active") # do we have it cached? if hasattr(self, "_thread_id"): return self._thread_id # no, look for it in the _active dict for tid, tobj in threading._active.items(): if tobj is self: self._thread_id = tid return tid # TODO: in python 2.6, there's a simpler way to do : self.ident raise AssertionError("could not determine the thread's id") def raiseExc(self, exctype): """Raises the given exception type in the context of this thread. If the thread is busy in a system call (time.sleep(), socket.accept(), ...), the exception is simply ignored. If you are sure that your exception should terminate the thread, one way to ensure that it works is: t = ThreadWithExc( ... ) ... t.raiseExc( SomeException ) while t.isAlive(): time.sleep( 0.1 ) t.raiseExc( SomeException ) If the exception is to be caught by the thread, you need a way to check that your thread has caught it. CAREFUL : this function is executed in the context of the caller thread, to raise an excpetion in the context of the thread represented by this instance. """ _async_raise( self._get_my_tid(), exctype )コメントで説明されているように、これは「万能薬」ではありません。スレッドが Python インタプリタの外側でビジー状態の場合、端末例外はキャッチされないためです~このコードこれを使用する合理的な方法は、スレッドに
特定の例外をキャッチさせてからクリーンアップ操作を実行させることです。こうすることで、タスクを終了し、適切にクリーンアップできます。
解決策 · 3割り込みメソッドと同様のことを実行したい場合は、thread.join メソッドを使用できます。join的原理就是依次检验线程池中的线程是否结束,没有结束就阻塞直到线程结束,如果结束则跳转执行下一个线程的join函数。 先看看这个: 1. 阻塞主进程,专注于执行多线程中的程序。 2. 多线程多join的情况下,依次执行各线程的join方法,前头一个结束了才能执行后面一个。 3. 无参数,则等待到该线程结束,才开始执行下一个线程的join。 4. 参数timeout为线程的阻塞时间,如 timeout=2 就是罩着这个线程2s 以后,就不管他了,继续执行下面的代码。
# coding: utf-8 # 多线程join import threading, time def doWaiting1(): print 'start waiting1: ' + time.strftime('%H:%M:%S') + "\n" time.sleep(3) print 'stop waiting1: ' + time.strftime('%H:%M:%S') + "\n" def doWaiting2(): print 'start waiting2: ' + time.strftime('%H:%M:%S') + "\n" time.sleep(8) print 'stop waiting2: ', time.strftime('%H:%M:%S') + "\n" tsk = [] thread1 = threading.Thread(target = doWaiting1) thread1.start() tsk.append(thread1) thread2 = threading.Thread(target = doWaiting2) thread2.start() tsk.append(thread2) print 'start join: ' + time.strftime('%H:%M:%S') + "\n" for tt in tsk: tt.join() print 'end join: ' + time.strftime('%H:%M:%S') + "\n"
デフォルトの結合方法はパラメータなし、ブロッキング モードで、他のスレッドは子スレッドの実行が終了した後にのみ実行されます。
1. 2 つのスレッドが同時に起動され、join 関数が実行されます。 2.waiting1 スレッドは 3 秒間実行 (待機) した後、終了します。 3.waiting2 スレッドが 8 秒間実行 (待機) した後、操作は終了します。 4. join関数(メインプロセスに戻る)が終了します。結合のパラメーター、つまりタイムアウト パラメーターを 2、つまり結合 (2) に変更すると、結果は次のようになります。 two 2 つのスレッドが同時に起動され、join 関数が実行されます。これはデフォルトの結合方法であり、スレッドの実行が開始された後に結合します。これに注意してください。結合後、メインスレッドは子スレッドが終了するまで待機する必要があります。帰りの本線です。
以上がPythonでスレッドを終了する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。