Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Apakah kaedah untuk menutup secara paksa benang, coroutine dan proses dalam Python?

Apakah kaedah untuk menutup secara paksa benang, coroutine dan proses dalam Python?

WBOY
WBOYke hadapan
2023-04-20 14:34:061667semak imbas

Berbilang-benang

Untuk keluar dalam utas dahulu, kita sering menggunakan kaedah: tetapkan syarat dalam keadaan gelung pelaksanaan sub-benang, dan apabila kita perlu keluar dari sub-benang, tetapkan keadaan , pada masa ini sub-benang akan keluar secara aktif, tetapi apabila sub-benang disekat, syarat-syarat tidak dinilai dalam gelung, dan masa menyekat tidak pasti, adalah mustahil bagi kita untuk mengitar semula benang . Pada masa ini, kaedah berikut diperlukan:

Benang Daemon:

Jika anda menetapkan benang sebagai benang daemon, ini bermakna anda mengatakan bahawa benang ini tidak penting dan tidak penting dalam proses. Apabila keluar, tidak perlu menunggu benang ini keluar.
Jika utas utama anda tidak perlu menunggu utas kanak-kanak tersebut selesai apabila keluar, kemudian tetapkan atribut daemon bagi utas ini. Iaitu, sebelum benang bermula (thread.start()), panggil fungsi setDeamon() untuk menetapkan bendera daemon bagi benang. (thread.setDaemon(True)) bermakna thread ini "tidak penting".

Jika anda ingin menunggu benang anak selesai sebelum keluar, maka jangan lakukan apa-apa. , atau panggil thread.setDaemon(False) secara eksplisit untuk menetapkan nilai daemon kepada false. Benang anak baharu akan mewarisi bendera daemon benang induk. Keseluruhan Python akan berakhir selepas semua benang bukan daemon keluar, iaitu, apabila tiada benang bukan daemon dalam proses.

Iaitu, benang kanak-kanak adalah benang bukan deamon, dan benang utama tidak terkeluar serta-merta

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

Adakah benang utama yang mengawalnya?

Benang daemon memerlukan utas utama untuk keluar untuk melengkapkan keluar sub-utas Berikut ialah kod, dan kemudian merangkumnya satu lapisan untuk mengesahkan sama ada utas utama perlu keluar .

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

Ganti utama Apabila fungsi dilaksanakan, didapati bahawa benang bulatan terus dilaksanakan selepas mencetak bendera 3 yang dihentikan.

Kesimpulan: Benang utama bertanggungjawab untuk memproses isyarat Hanya dengan memastikan ia hidup boleh isyarat diproses dengan betul.

Melemparkan pengecualian dalam utas Python

Walaupun menggunakan PyThreadState_SetAsyncExc boleh memenuhi keluar terus kami dari utas dalam kebanyakan kes kaedah PyThreadState_SetAsyncExc hanya melaksanakan "pelan" untuk keluar. Ia tidak membunuh benang, terutamanya apabila ia melaksanakan perpustakaan C luaran. Cuba sleep(100) kaedah anda untuk membunuh satu. Ia akan "dibunuh" selepas 100 saat. while flag: Ia berfungsi sama seperti ->flag = Kaedah palsu.

Jadi apabila sub-benang mempunyai fungsi menyekat seperti tidur, semasa proses tidur, sub-benang tidak dapat bertindak balas dan akan ditangkap oleh utas utama, mengakibatkan ketidakupayaan untuk membatalkan sub-benang. Sebenarnya, apabila utas sedang tidur, ia tidak boleh menggunakan fungsi async_raise secara langsung untuk mematikan utas, kerana jika utas sibuk di luar penterjemah Python, ia tidak akan menangkap gangguan

Kod sampel:

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

operasi signal.pthread_kill:

Ini adalah yang paling hampir dengan operasi bunuh pthread dalam Unix yang saya lihat beberapa kegunaan di Internet, tetapi saya tidak menemui penggunaannya dalam perpustakaan ini apabila saya mengesahkannya dikeluarkan dalam versi berikutnya.

Apakah kaedah untuk menutup secara paksa benang, coroutine dan proses dalam Python?Ini ialah beberapa contoh kod yang saya lihat dalam talian, tetapi ia tidak boleh dilaksanakan Jika sesiapa tahu cara menggunakannya, anda boleh berkomunikasi.

Pemprosesan berbilang
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)

pemprosesan berbilang ialah pakej yang menyokong proses pemijahan menggunakan API yang serupa dengan modul penjalinan. Pakej multiprocessing menyediakan kedua-dua operasi serentak tempatan dan jauh, dengan berkesan memintas kunci penterjemah global dengan menggunakan proses kanak-kanak dan bukannya benang. Oleh itu, modul multiprocessing membolehkan pengaturcara memanfaatkan sepenuhnya pelbagai pemproses pada mesin tertentu.

Pustaka berbilang proses digunakan, dan kami boleh memanggil fungsi dalamannya ditamatkan untuk membantu kami mengeluarkannya. Sebagai contoh, t.terminate() boleh memaksa proses anak untuk keluar.

Walau bagaimanapun, kaedah interaksi menggunakan data berbilang proses adalah lebih menyusahkan memori kongsi, paip atau baris gilir mesej mesti digunakan untuk interaksi data antara proses anak dan proses induk.

Kod sampel adalah seperti berikut:

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

Coroutine juga dipanggil micro-threads. Ia adalah cara lain untuk mencapai multi-tasking unit pelaksanaan yang lebih kecil yang biasanya berjalan pada satu proses dan satu utas. Oleh kerana ia mempunyai konteks CPU sendiri, ia boleh menukar tugas melalui gelung peristiwa yang mudah, yang lebih cekap daripada menukar antara proses dan benang, kerana penukaran antara proses dan benang dilakukan oleh sistem pengendalian.

Python bergantung terutamanya pada dua perpustakaan untuk melaksanakan coroutine: asyncio (asyncio ialah perpustakaan standard yang diperkenalkan daripada Python 3.4, yang secara langsung mempunyai sokongan terbina dalam untuk IO asynchronous coroutine. Model pengaturcaraan asyncio pada asasnya ialah mesej Gelung , kami biasanya mentakrifkan fungsi (atau tugas) coroutine terlebih dahulu, dapatkan gelung gelung peristiwa daripada modul asyncio, dan kemudian buang tugas coroutine (atau senarai tugas) yang perlu dilaksanakan ke dalam gelung untuk pelaksanaan, dengan itu merealisasikan IO tak segerak) dan gevent (Gevent ialah perpustakaan pihak ketiga yang boleh dengan mudah melaksanakan pengaturcaraan segerak atau tak segerak serentak melalui gevent. Mod utama yang digunakan dalam gevent ialah Greenlet, iaitu coroutine ringan yang disambungkan kepada Python dalam bentuk modul sambungan C.).

由于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()

Atas ialah kandungan terperinci Apakah kaedah untuk menutup secara paksa benang, coroutine dan proses dalam Python?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam