4

Python モジュールthreadingThreadには、別のスレッドでプロセスと関数を実行するために使用されるオブジェクトがあります。このオブジェクトにはstartメソッドがありますが、メソッドはありませんstop。単純なメソッドThreadの呼び出しを停止できない理由は何ですか? stopメソッドを使用するのが不便な場合を想像できjoinます...

4

5 に答える 5

10

startスレッドのターゲットを起動するだけなので、ジェネリックにすることができますが、ジェネリックは何をstopしますか? スレッドの動作によっては、ネットワーク接続を閉じたり、システム リソースを解放したり、ファイルやその他のストリームをダンプしたり、その他の重要なカスタム タスクをいくつでも実行したりする必要があります。これらのことのほとんどを一般的な方法で実行できるシステムは、各スレッドに非常に多くのオーバーヘッドを追加するため、その価値がなくなり、非常に複雑になり、特殊なケースで機能しなくなるため、ほとんど機能しなくなります。と。作成されたすべてのスレッドをメインスレッドで ing せずに追跡しjoin、実行状態を確認して、メインスレッドがシャットダウンしたときに何らかの終了メッセージを渡すことができます。

于 2013-01-23T14:45:16.220 に答える
7

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)
于 2013-01-23T20:28:21.623 に答える
5

信頼できる方法でスレッドを強制終了することは、それほど簡単ではありません。必要なクリーンアップについて考えてみてください。どのロック (他のスレッドと共有されている可能性があります!) を自動的に解放する必要がありますか? そうしないと、簡単にデッドロックに陥ります。

より良い方法は、適切なシャットダウンを自分で実装してから設定することです

mythread.shutdown = True
mythread.join()

スレッドを停止します。

もちろん、スレッドは次のようにする必要があります

while not this.shutdown:
    continueDoingSomething()
releaseThreadSpecificLocksAndResources()

シャットダウンフラグを頻繁にチェックします。または、OS 固有のシグナル伝達メカニズムに依存して、スレッドに割り込み、割り込みをキャッチしてからクリーンアップすることもできます。

クリーンアップは最も重要な部分です!

于 2013-01-23T14:40:34.107 に答える
1

スレッドの停止は、プログラマーが実装する必要があります。スレッドをチェックするように設計するなど、すぐに終了するように要求があります。Python (または任意のスレッド言語) でスレッドを停止できる場合は、停止したばかりのコードが作成されます。これはバグが発生しやすいなどです。

スレッドを強制終了/停止したときに、スレッドが出力をファイルに書き込んでいると想像してください。その後、ファイルは未完成で破損している可能性があります。ただし、停止したいスレッドに単純に信号を送った場合、ファイルを閉じたり、削除したりすることができます。プログラマーであるあなたは、それを処理する方法を決定しました。Python は推測できません。

マルチスレッド理論を読んでおくことをお勧めします。まともなスタート: http://en.wikipedia.org/wiki/Multithreading_(software)#Multithreading

于 2013-01-23T14:41:49.577 に答える
0

一部のプラットフォームでは、スレッドを強制的に「停止」することはできません。スレッドが割り当てられたリソースをクリーンアップできなくなるため、これを行うのも悪いことです。また、スレッドが I/O などの重要なことを実行しているときに発生する可能性があります。

于 2013-01-23T14:40:24.677 に答える