ホームページ  >  記事  >  バックエンド開発  >  Pythonでスレッドを終了する方法

Pythonでスレッドを終了する方法

藏色散人
藏色散人オリジナル
2021-03-02 14:02:3460350ブラウズ

Python でスレッドを終了する方法: 1. stop 関数を呼び出し、join 関数を使用してスレッドが適切に終了するのを待ちます; 2. Python スレッドで例外を発生させます; 3. 「thread. join" を実行してスレッドを終了します。

Pythonでスレッドを終了する方法

この記事の動作環境: Windows 7 システム、Python バージョン 3.5、DELL G3 コンピューター。

前書き・ゼロ

Python でスレッドを終了するには、set/check--->フラグまたはロックを行うのが従来の方法であることはわかっています。

この方法は良いですか?

あまり良くないはずです。なぜなら、すべてのプログラミング言語において、スレッドを突然終了することは、いかなる場合でも良い設計パターンではないからです。

同時に

#次のような状況はさらに悪化する場合もあります。

    スレッドが重要なリソースを開いたとき、読み取り可能および書き込み可能なファイルを開くなど、合理的に閉じる必要があります。
  • スレッドは他のスレッドをいくつか作成しており、これらのスレッドも閉じる必要があります (子孫スレッドがさまよう危険があります!)。
簡単に言うと、スレッドの大規模なグループが共通のリソースと同じ場所に配置されています。スレッドの 1 つを「離れる」必要があります。このスレッドがたまたまリソースを占有している場合、そのスレッドは削除されます。リソースがロックされていて誰も入手できないだけなのです。不死者の育成をテーマにした小説のプロットに少し似ていませんか?

なぜスレッドには開始だけがあって終了がないのかご存知ですか?

ご存知のとおり、スレッドは通常、ネットワーク接続、システム リソースの解放、ストリーミング ファイルのダンプに使用されます。これらはすべて 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 関数が実行されます。
  1. wating1 スレッドは 3 秒間の実行 (待機) 後に完了しました。
  2. 参加終了 (2 が 2 つ、合計 4 つ、36-32=4、正解)。
  3. waiting2 スレッドは、join で指定された待機時間 (4 秒) 内に完了しなかったため、後で実行を完了しました。
join(2) は次のとおりです: サブスレッドに 2 秒与えます。2 秒ごとに終了します。ほんのわずかな可能性が心配です!

以上がPythonでスレッドを終了する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。