ホームページ  >  記事  >  バックエンド開発  >  Pythonでスレッド、コルーチン、プロセスを強制的に閉じる方法は何ですか?

Pythonでスレッド、コルーチン、プロセスを強制的に閉じる方法は何ですか?

WBOY
WBOY転載
2023-04-20 14:34:061660ブラウズ

マルチスレッド

まず第一に、スレッドを終了するとき、私たちはよく次のような方法を使用します。サブスレッド実行のループ条件によって条件が設定され、サブスレッドを終了する必要があるときは、スレッド、条件を設定します。このとき、サブスレッドは積極的に終了しますが、サブスレッドがブロックされると、ループ内で条件が判断されず、ブロック時間が不確実になるため、リサイクルすることができなくなります。スレッド。現時点では、次のメソッドが必要です。

デーモン スレッド:

スレッドをデーモン スレッドとして設定すると、このスレッドは重要ではなく、今後も使用されないことを意味します。終了する場合、このスレッドが終了するのを待つ必要はありません。
メインスレッドが終了するときに、これらの子スレッドが完了するのを待つ必要がない場合は、これらのスレッドのデーモン属性を設定します。つまり、スレッドが開始される (thread.start()) 前に、setDeamon() 関数を呼び出してスレッドのデーモン フラグを設定します。 (thread.setDaemon(True)) は、このスレッドが「重要ではない」ことを意味します。

子スレッドが完了するまで待ってから終了する場合は、何もする必要はありません。 、または明示的に thread.setDaemon(False) を呼び出してデーモン値を false に設定します。新しい子スレッドは、親スレッドのデーモン フラグを継承します。 Python 全体は、すべての非デーモン スレッドが終了した後、つまりプロセス内に非デーモン スレッドがなくなったときに終了します。

つまり、サブスレッドは非デーモン スレッドであり、メイン スレッドはすぐには終了しません。

import threading
import time
import gc
import datetime

def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')


if __name__ == "__main__":
   t = threading.Thread(target=circle)
   t.setDaemon(True)
   t.start()
   time.sleep(1)
   # stop_thread(t)
   # print('stoped threading Thread') 
   current_time = datetime.datetime.now()
   print(str(current_time) + ' stoped after') 
   gc.collect()
   while True:
      time.sleep(1)
      current_time = datetime.datetime.now()
      print(str(current_time) + ' end circle')

それを制御しているのはメイン スレッドですか?

デーモン スレッドは、サブスレッドの終了を完了するためにメイン スレッドが終了する必要があります。次のコードは、メイン スレッドが終了する必要があるかどうかを確認するために 1 つのレイヤーをカプセル化します

def Daemon_thread():
   circle_thread= threading.Thread(target=circle)
#    circle_thread.daemon = True
   circle_thread.setDaemon(True)
   circle_thread.start()   
   while running:
        print('running:',running) 
        time.sleep(1)
   print('end..........') 


if __name__ == "__main__":
    t = threading.Thread(target=Daemon_thread)
    t.start()   
    time.sleep(3)
    running = False
    print('stop running:',running) 
    print('stoped 3') 
    gc.collect()
    while True:
        time.sleep(3)
        print('stoped circle')

main 関数の実行を置き換えると、停止 3 フラグを出力した後もサークル スレッドが実行を継続していることがわかりました。

結論: メイン スレッドはシグナルの処理に依存しており、メイン スレッドが生きていることを確認することによってのみ、シグナルを正しく処理できます。

Python スレッドでの例外のスロー

PyThreadState_SetAsyncExc を使用すると、ほとんどの場合、スレッドから直接終了できますが、PyThreadState_SetAsyncExc メソッドは、スレッドが終了するための「計画」を実行するだけです。特に外部 C ライブラリを実行している場合、スレッドは強制終了されません。 1 つを殺す方法として sleep(100) を試してください。 100秒後に「強制終了」されます。 while flag: ->flag = False メソッドと同じように機能します。

そのため、サブスレッドにスリープなどのブロック機能がある場合、スリープ処理中にサブスレッドは応答できず、メインスレッドに捕捉されてしまい、サブスレッドをキャンセルできなくなります。実際、スレッドがスリープしているときは、async_raise 関数を直接使用してスレッドを強制終了することはできません。これは、スレッドが Python インタプリタの外側でビジー状態の場合、割り込みをキャッチできないためです。

サンプル コード:

import ctypes
import inspect
import threading
import time
import gc
import datetime

def async_raise(tid, exctype):
   """raises the exception, performs cleanup if needed"""
   tid = ctypes.c_long(tid)
   if not inspect.isclass(exctype):
      exctype = type(exctype)
   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, None)
      raise SystemError("PyThreadState_SetAsyncExc failed")
      
def stop_thread(thread):
   async_raise(thread.ident, SystemExit)
   
def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')

if __name__ == "__main__":
   t = threading.Thread(target=circle)
   t.start()
   time.sleep(1)
   stop_thread(t)
   print('stoped threading Thread') 
   current_time = datetime.datetime.now()
   print(str(current_time) + ' stoped after') 
   gc.collect()
   while True:
      time.sleep(1)
      current_time = datetime.datetime.now()
      print(str(current_time) + ' end circle')

signal.pthread_kill 操作:

これは、Unix の pthread kill 操作に最も近いものです。インターネット上でいくつかの使用法を見ましたが、このライブラリで使用法を見つけられませんでした。

これは、Python の公式シグナル説明ドキュメントの記述から、バージョン 3.3 の新機能であることがわかりました。私自身は python3.10 ですが、pthread_kill はありません。これは削除される可能性があります。それ以降のバージョン。

Pythonでスレッド、コルーチン、プロセスを強制的に閉じる方法は何ですか?

これはネットで見たサンプルコードですが、実行することはできません。使い方を知っている方がいらっしゃいましたら、ご連絡ください。

from signal import pthread_kill, SIGTSTP
from threading import Thread
from itertools import count
from time import sleep

def target():
    for num in count():
        print(num)
        sleep(1)

thread = Thread(target=target)
thread.start()
sleep(5)
signal.pthread_kill(thread.ident, SIGTSTP)

Multiprocessing

Multiprocessing は、スレッド モジュールと同様の API を使用して生成プロセスをサポートするパッケージです。マルチプロセッシング パッケージはローカルとリモートの両方の同時操作を提供し、スレッドの代わりに子プロセスを使用することでグローバル インタプリタ ロックを効果的にバイパスします。したがって、マルチプロセッシング モジュールを使用すると、プログラマは特定のマシン上の複数のプロセッサを最大限に活用できます。

マルチプロセス ライブラリが使用されており、その内部関数 terminate を呼び出して解放することができます。たとえば、 t.terminate() は子プロセスを強制的に終了できます。

ただし、マルチプロセスデータを使用した対話方法はより煩雑であり、子プロセスと親プロセス間のデータ対話には共有メモリ、パイプ、またはメッセージキューを使用する必要があります。

サンプル コードは次のとおりです:

import time
import gc
import datetime
import multiprocessing

def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')


if __name__ == "__main__":
    t = multiprocessing.Process(target=circle, args=())
    t.start()
    # Terminate the process
    current_time = datetime.datetime.now()
    print(str(current_time) + ' stoped before') 
    time.sleep(1)
    t.terminate()  # sends a SIGTERM
    current_time = datetime.datetime.now()
    print(str(current_time) + ' stoped after') 
    gc.collect()
    while True:
        time.sleep(3)
        current_time = datetime.datetime.now()
        print(str(current_time) + ' end circle')

複数のコルーチン

コルーチン (コルーチン) はマイクロスレッドとも呼ばれ、マルチタスクを実現する別の方法です。スレッドよりも効率的. 通常、単一プロセスおよび単一スレッドで実行される小さな実行ユニット。独自の CPU コンテキストを持っているため、単純なイベント ループを通じてタスクを切り替えることができます。これは、プロセスとスレッド間の切り替えがオペレーティング システムによって実行されるため、プロセスとスレッド間の切り替えよりも効率的です。

Python は主に 2 つのライブラリに依存してコルーチンを実装します: asyncio (asyncio は Python 3.4 から導入された標準ライブラリで、コルーチン非同期 IO のサポートが直接組み込まれています。asyncio のプログラミング モデルの本質はメッセージ ループです。 、通常、最初にコルーチン関数 (またはタスク) を定義し、asyncio モジュールからイベント ループ ループを取得してから、実行する必要があるコルーチン タスク (またはタスク リスト) をループにスローして実行することで、非同期 IO を実現します)および gevent (Gevent は、gevent を介して同時同期または非同期プログラミングを簡単に実装できるサードパーティ ライブラリです。gevent で使用される主なモードは Greenlet で、これは C 拡張モジュールの形式で Python に接続された軽量のコルーチンです。)

由于asyncio已经成为python的标准库了无需pip安装即可使用,这意味着asyncio作为Python原生的协程实现方式会更加流行。本文仅会介绍asyncio模块的退出使用。

使用协程取消,有两个重要部分:第一,替换旧的休眠函数为多协程的休眠函数;第二取消使用cancel()函数。

其中cancel() 返回值为 True 表示 cancel 成功。

示例代码如下:创建一个coroutine,然后调用run_until_complete()来初始化并启动服务器来调用main函数,判断协程是否执行完成,因为设置的num协程是一个死循环,所以一直没有执行完,如果没有执行完直接使用 cancel()取消掉该协程,最后执行成功。

import asyncio
import time


async def num(n):
    try:
        i = 0
        while True:
            print(f'i={i} Hello')
            i=i+1
            # time.sleep(10)
            await asyncio.sleep(n*0.1)
        return n
    except asyncio.CancelledError:
        print(f"数字{n}被取消")
        raise


async def main():
    # tasks = [num(i) for i in range(10)]
    tasks = [num(10)]
    complete, pending = await asyncio.wait(tasks, timeout=0.5)
    for i in complete:
        print("当前数字",i.result())
    if pending:
        print("取消未完成的任务")
        for p in pending:
            p.cancel()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

以上がPythonでスレッド、コルーチン、プロセスを強制的に閉じる方法は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。