Rumah > Artikel > pembangunan bahagian belakang > Apakah kaedah untuk menutup secara paksa benang, coroutine dan proses dalam Python?
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:
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.
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')
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.
Ini ialah beberapa contoh kod yang saya lihat dalam talian, tetapi ia tidak boleh dilaksanakan Jika sesiapa tahu cara menggunakannya, anda boleh berkomunikasi.
Pemprosesan berbilangfrom 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)
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 coroutineimport 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')
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!