Python マルチスレッド プログラミング: スレッドを正常に閉じる方法

並行プログラミングでは、新しいスレッドを作成し、そこでタスクを実行し、何らかの理由でスレッドを停止することを決定する場合があります。例えば:

  • スレッド タスクの結果は必要なくなりました。
  • 申し込みは終了しています。
  • スレッドの実行中に例外が発生した可能性があります

Python マルチスレッド プログラミングの知識については、「浅いものから深いものまで Python マルチスレッド プログラミングをマスターする」を参照してください。

Threading モジュールの Thread クラスには、スレッドを閉じるメソッドがありません。子スレッドが適切に閉じられていない場合、次の問題が発生する可能性があります。

  • メインスレッドが終了した後も、子スレッドは実行され続け、ゾンビプロセスになります。
  • 子スレッドによって開かれたファイルが適切に閉じることができず、データが損失しました。
  • 子スレッドによって開かれたデータベースが更新の送信に失敗したため、データが損失しました。

では、スレッドを正しく閉じるにはどうすればよいでしょうか?

1. Python がデフォルトでスレッドを閉じる方法

スレッド オブジェクトが作成されたら、start (メソッドを呼び出して実行します。実行が完了すると、自動的に閉じられます。次のサンプル コードのように:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import threading    #导入threading 模块
import time

# 定义任务函数 print_time
def print_time ( threadName ,delay ):
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        print("%s: %s \n" % (threadName,time.ctime(time.time())))

# 定义任务函数 print_cube
def print_cube(num):
    #pring cube
    print("Cube:{} \n".format(num*num*num))
 
# 创建两个线程
if __name__ == "__main__":
        # 创建两个子线程
        t1 = threading.Thread( target=print_cube,args=(10,))
        t2 = threading.Thread( target=print_time,args=("Thread-2",4,))
        #start threads
        t1.start()   # start 后,子线程开始运行
        t2.start()
        t1.join()     #join 命令:让主线程暂停运行,等待子线程运行结束。
        t2.join()
        print("Done") # The statement is executed after sub threads done

2. スレッドを正常に閉じるにはどうすればよいですか?

前のセクションの例では、スレッドの実行時間は短く、すぐに終了する可能性があるため、メインスレッドはスレッドが終了するまで待つことができます。ただし、子スレッドがサービスの提供や監視タスクの実行など、時間のかかるタスクを実行する場合、子スレッド内で永続的なループが発生する可能性があります。このとき、子スレッド オブジェクトは start() を実行した後、実行状態の処理を続行します。

Windowsシステムでは、アプリケーションが直接終了すると、当然サブスレッドは強制終了されますが、アクセス中のファイルが正しく閉じられるなど、サブスレッドが実行中のタスクに影響を及ぼし、データが失われる可能性があります。 、など。
Linux システムでは、kill コマンドを使用してプロセスを強制終了するなど、アプリケーションが直接終了すると、適切に閉じられていないサブスレッドが引き続き実行され、ゾンビ プロセスになる可能性があります。

では、子スレッドを正常に停止するにはどうすればよいでしょうか? 2 つのアイデアがあります:
1) グローバル状態変数を設定してスレッドを閉じる
2) threading.Event オブジェクトを通じてスレッドを閉じる

次の例は、2 つのメソッドの実装プロセスを示しています。

2.1. グローバル変数を使用してスレッドを閉じる

実装手順:

  • スレッド内に状態変数を追加する
  • スレッド ループ本体で状態変数を確認し、それが False の場合はループを終了します。
  • メインスレッドがスレッドを閉じる必要がある場合は、子スレッド オブジェクトの状態変数を False に設定します。

2.1.1 スレッドクラスによって実装されたスレッドを閉じる

class CountdownTask:
      
    def __init__(self):
          self._running = True   # 定义线程状态变量
      
	def terminate(self):
	    self._running = False 
	      
	def run(self, n):
	    # run方法的主循环条件加入对状态变量的判断
	    while self._running and n > 0:
	        print('T-minus', n)
	        n -= 1
	        time.sleep(5)
	    print("thread is ended") 
  
c = CountdownTask()
th = Thread(target = c.run, args =(10, ))
th.start()
# 对于耗时线程,没必要再用join()方法了,注意主线程通常也需要有个监控循环
# … any code … 
# Signal termination
q = input("please press any key to quit ")
c.terminate() 

2.1.2 機能スレッドの終了

機能スレッドを閉じると、グローバル変数を状態変数として使用できます

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')


2.2. threading.Event オブジェクトを使用して子スレッドを閉じる

2.2.1 イベントメカニズムの動作原理

イベントはスレッド間で通信する方法です。その機能はグローバル フラグに相当し、メイン スレッドはイベント オブジェクトの状態を制御することでサブスレッドのペースを調整します。

使い方

  1. メインスレッドはイベントオブジェクトを作成し、それをパラメータとして子スレッドに渡します。
  2. メインスレッドは、オブジェクトを true に設定するset()メソッドとfalse に設定するメソッドを使用できます。eventclear()
  3. 子スレッドのループ本体で、イベント オブジェクトの値を確認し、それが True の場合はループを終了します。
  4. 子スレッドを使用すると、event.wait()イベント オブジェクトが true に設定されるまで現在の子プロセスをブロックできます。

イベントクラスの共通メソッド

  • set() は True を設定します
  • clear() は False を設定します。
  • wait() は、フラグが true に変更されるまでプロセスを待機させます。
  • is_set() イベント オブジェクトをクエリします。true に設定されている場合は True を返し、それ以外の場合は False を返します。
if event.is_set():
     # do something before end worker 
     break

このメソッドの利点は、Event オブジェクトがスレッドセーフで高速であることです。時間のかかるスレッドを閉じるには、このメソッドを使用することをお勧めします。

2.2.2 完全なコード:

from time import sleep
from threading import Thread
from threading import Event
 
# define task function
def task(event):
    # execute a task in a loop
    for i in range(100):
        # block for a moment
        sleep(1)
        # check for stop
        if event.is_set():
            # 在此添加退出前要做的工作,如保存文件等
            break
        # report a message
        print('Worker thread running...')
    print('Worker is ended')
 
# create the event
event = Event()
# create a thread 
thread = Thread(target=task, args=(event,))
# start the new thread
thread.start()
# block for a while
sleep(3)
# stop the worker thread
print('Main stopping thread')
event.set()
# 这里是为了演示,实际开发时,主进程有事件循环,耗时函数不需要调用join()方法
thread.join()

子スレッドはタスク ループを実行し、ループするたびにイベント オブジェクトをチェックします。オブジェクトが false のままであれば、スレッドの停止はトリガーされません。

メインスレッドがイベント オブジェクトの set() メソッドを呼び出した後、サブスレッドのループ本体でイベント オブジェクトの is_set() メソッドを呼び出し、イベント オブジェクトが True であることが確認された場合、直ちに終了します。タスクループを終了し、操作を終了します。

おすすめ

転載: blog.csdn.net/captain5339/article/details/128360804
おすすめ