Python モジュールthreadingThread
には、別のスレッドでプロセスと関数を実行するために使用されるオブジェクトがあります。このオブジェクトにはstart
メソッドがありますが、メソッドはありませんstop
。単純なメソッドThread
の呼び出しを停止できない理由は何ですか? stop
メソッドを使用するのが不便な場合を想像できjoin
ます...
5 に答える
start
スレッドのターゲットを起動するだけなので、ジェネリックにすることができますが、ジェネリックは何をstop
しますか? スレッドの動作によっては、ネットワーク接続を閉じたり、システム リソースを解放したり、ファイルやその他のストリームをダンプしたり、その他の重要なカスタム タスクをいくつでも実行したりする必要があります。これらのことのほとんどを一般的な方法で実行できるシステムは、各スレッドに非常に多くのオーバーヘッドを追加するため、その価値がなくなり、非常に複雑になり、特殊なケースで機能しなくなるため、ほとんど機能しなくなります。と。作成されたすべてのスレッドをメインスレッドで ing せずに追跡しjoin
、実行状態を確認して、メインスレッドがシャットダウンしたときに何らかの終了メッセージを渡すことができます。
Thread.stop
次のコード例に示すように、メソッドを実装することは間違いなく可能です。
import threading
import sys
class StopThread(StopIteration): pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
################################################################################
import time
def main():
test = Thread2(target=printer)
test.start()
time.sleep(1)
test.stop()
test.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
if __name__ == '__main__':
main()
このThread3
クラスは、クラスよりも約 33% 高速にコードを実行するようですThread2
。
補遺:
Python の C API とctypes
モジュールの使用に関する十分な知識があれば、必要に応じてスレッドを停止するはるかに効率的な方法を作成できます。使用上の問題sys.settrace
は、トレース機能が各命令の後に実行されることです。中止する必要があるスレッドで代わりに非同期例外が発生した場合、実行速度のペナルティは発生しません。次のコードは、この点に関してある程度の柔軟性を提供します。
#! /usr/bin/env python3
import _thread
import ctypes as _ctypes
import threading as _threading
_PyThreadState_SetAsyncExc = _ctypes.pythonapi.PyThreadState_SetAsyncExc
# noinspection SpellCheckingInspection
_PyThreadState_SetAsyncExc.argtypes = _ctypes.c_ulong, _ctypes.py_object
_PyThreadState_SetAsyncExc.restype = _ctypes.c_int
# noinspection PyUnreachableCode
if __debug__:
# noinspection PyShadowingBuiltins
def _set_async_exc(id, exc):
if not isinstance(id, int):
raise TypeError(f'{id!r} not an int instance')
if not isinstance(exc, type):
raise TypeError(f'{exc!r} not a type instance')
if not issubclass(exc, BaseException):
raise SystemError(f'{exc!r} not a BaseException subclass')
return _PyThreadState_SetAsyncExc(id, exc)
else:
_set_async_exc = _PyThreadState_SetAsyncExc
# noinspection PyShadowingBuiltins
def set_async_exc(id, exc, *args):
if args:
class StateInfo(exc):
def __init__(self):
super().__init__(*args)
return _set_async_exc(id, StateInfo)
return _set_async_exc(id, exc)
def interrupt(ident=None):
if ident is None:
_thread.interrupt_main()
else:
set_async_exc(ident, KeyboardInterrupt)
# noinspection PyShadowingBuiltins
def exit(ident=None):
if ident is None:
_thread.exit()
else:
set_async_exc(ident, SystemExit)
class ThreadAbortException(SystemExit):
pass
class Thread(_threading.Thread):
def set_async_exc(self, exc, *args):
return set_async_exc(self.ident, exc, *args)
def interrupt(self):
self.set_async_exc(KeyboardInterrupt)
def exit(self):
self.set_async_exc(SystemExit)
def abort(self, *args):
self.set_async_exc(ThreadAbortException, *args)
信頼できる方法でスレッドを強制終了することは、それほど簡単ではありません。必要なクリーンアップについて考えてみてください。どのロック (他のスレッドと共有されている可能性があります!) を自動的に解放する必要がありますか? そうしないと、簡単にデッドロックに陥ります。
より良い方法は、適切なシャットダウンを自分で実装してから設定することです
mythread.shutdown = True
mythread.join()
スレッドを停止します。
もちろん、スレッドは次のようにする必要があります
while not this.shutdown:
continueDoingSomething()
releaseThreadSpecificLocksAndResources()
シャットダウンフラグを頻繁にチェックします。または、OS 固有のシグナル伝達メカニズムに依存して、スレッドに割り込み、割り込みをキャッチしてからクリーンアップすることもできます。
クリーンアップは最も重要な部分です!
スレッドの停止は、プログラマーが実装する必要があります。スレッドをチェックするように設計するなど、すぐに終了するように要求があります。Python (または任意のスレッド言語) でスレッドを停止できる場合は、停止したばかりのコードが作成されます。これはバグが発生しやすいなどです。
スレッドを強制終了/停止したときに、スレッドが出力をファイルに書き込んでいると想像してください。その後、ファイルは未完成で破損している可能性があります。ただし、停止したいスレッドに単純に信号を送った場合、ファイルを閉じたり、削除したりすることができます。プログラマーであるあなたは、それを処理する方法を決定しました。Python は推測できません。
マルチスレッド理論を読んでおくことをお勧めします。まともなスタート: http://en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
一部のプラットフォームでは、スレッドを強制的に「停止」することはできません。スレッドが割り当てられたリソースをクリーンアップできなくなるため、これを行うのも悪いことです。また、スレッドが I/O などの重要なことを実行しているときに発生する可能性があります。