En general, matar fils bruscament es considera una mala pràctica de programació. Matar un fil bruscament pot deixar obert un recurs crític que s'ha de tancar correctament. Però és possible que vulgueu matar un fil un cop hagi passat un període de temps específic o s'ha generat una interrupció. Hi ha diversos mètodes amb els quals podeu matar un fil a Python.
- Generant excepcions en un fil de Python
- Establir/restablir la bandera d'aturada
- Utilitzant rastres per matar fils
- Ús del mòdul multiprocessament per eliminar fils
- Matar el fil de Python configurant-lo com a dimoni
- Utilitzant una funció oculta _stop()
Generant excepcions en un fil de Python:
Aquest mètode utilitza la funció PyThreadState_SetAsyncExc() per generar una excepció al fil a. Per exemple,
Python 3
història en java
# Python program raising> # exceptions in a python> # thread> import> threading> import> ctypes> import> time> > class> thread_with_exception(threading.Thread):> > def> __init__(> self> , name):> > threading.Thread.__init__(> self> )> > self> .name> => name> > > def> run(> self> ):> > # target function of the thread class> > try> :> > while> True> :> > print> (> 'running '> +> self> .name)> > finally> :> > print> (> 'ended'> )> > > def> get_id(> self> ):> > # returns id of the respective thread> > if> hasattr> (> self> ,> '_thread_id'> ):> > return> self> ._thread_id> > for> id> , thread> in> threading._active.items():> > if> thread> is> self> :> > return> id> > > def> raise_exception(> self> ):> > thread_id> => self> .get_id()> > res> => ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,> > ctypes.py_object(SystemExit))> > if> res>> 1> :> > ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,> 0> )> > print> (> 'Exception raise failure'> )> > t1> => thread_with_exception(> 'Thread 1'> )> t1.start()> time.sleep(> 2> )> t1.raise_exception()> t1.join()> |
>
>
Quan executem el codi anterior en una màquina i notareu, tan bon punt es crida a la funció raise_exception(), la funció de destinació run() acaba. Això es deu al fet que tan aviat com es planteja una excepció, el control del programa surt del bloc try i la funció run() s'acaba. Després d'això, es pot cridar la funció join() per matar el fil. En absència de la funció run_exception(), la funció de destinació run() continua funcionant per sempre i la funció join() mai es crida per matar el fil.
Establir/restablir la bandera d'aturada:
Per tal de matar un fil, podem declarar un indicador d'aturada i aquest indicador es comprovarà de tant en tant pel fil. Per exemple
Python 3
# Python program showing> # how to kill threads> # using set/reset stop> # flag> 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'> )> |
>
>
En el codi anterior, tan bon punt s'estableix la variable global stop_threads, la funció de destinació run() acaba i el fil t1 es pot eliminar mitjançant t1.join(). Però es pot abstenir d'utilitzar la variable global per certs motius. En aquestes situacions, es poden passar objectes de funció per proporcionar una funcionalitat similar a la que es mostra a continuació.
Python 3
# Python program killing> # threads using stop> # flag> import> threading> import> time> def> run(stop):> > while> True> :> > print> (> 'thread running'> )> > if> stop():> > break> > def> main():> > stop_threads> => False> > t1> => threading.Thread(target> => run, args> => (> lambda> : stop_threads, ))> > t1.start()> > time.sleep(> 1> )> > stop_threads> => True> > t1.join()> > print> (> 'thread killed'> )> main()> |
>
>
L'objecte de funció passat al codi anterior sempre retorna el valor de la variable local stop_threads. Aquest valor es verifica a la funció run() i tan bon punt es reinicia stop_threads, la funció run() finalitza i el fil es pot eliminar.
Ús de traces per matar fils:
Aquest mètode funciona mitjançant la instal·lació rastres en cada fil. Cada rastre s'acaba amb la detecció d'algun estímul o bandera, matant així a l'instant el fil associat. Per exemple
Python 3
símbol de derivada parcial làtex
# Python program using> # traces to kill threads> import> sys> import> trace> import> threading> import> time> class> thread_with_trace(threading.Thread):> > def> __init__(> self> ,> *> args,> *> *> keywords):> > threading.Thread.__init__(> self> ,> *> args,> *> *> keywords)> > self> .killed> => False> > def> start(> self> ):> > self> .__run_backup> => self> .run> > self> .run> => self> .__run> > threading.Thread.start(> self> )> > def> __run(> self> ):> > sys.settrace(> self> .globaltrace)> > self> .__run_backup()> > self> .run> => self> .__run_backup> > def> globaltrace(> self> , frame, event, arg):> > if> event> => => 'call'> :> > return> self> .localtrace> > else> :> > return> None> > def> localtrace(> self> , frame, event, arg):> > if> self> .killed:> > if> event> => => 'line'> :> > raise> SystemExit()> > return> self> .localtrace> > def> kill(> self> ):> > self> .killed> => True> def> func():> > while> True> :> > print> (> 'thread running'> )> t1> => thread_with_trace(target> => func)> t1.start()> time.sleep(> 2> )> t1.kill()> t1.join()> if> not> t1.isAlive():> > print> (> 'thread killed'> )> |
>
>
En aquest codi, start() es modifica lleugerament per establir la funció de traça del sistema utilitzant settrace() . La funció de traça local es defineix de manera que, sempre que s'estableixi la marca de matança (killed) del fil respectiu, es genera una excepció SystemExit a l'execució de la següent línia de codi, que acaba amb l'execució de la funció de destinació. Ara el fil es pot eliminar amb join().
Utilitzant el mòdul multiprocessament per matar fils:
El mòdul de multiprocessament de Python us permet generar processos de la mateixa manera que genereu fils mitjançant el mòdul de fils. La interfície del mòdul multithreading és similar a la del mòdul threading. Per exemple, en un codi donat hem creat tres fils (processos) que compten de l'1 al 9.
Python 3
# Python program creating> # three threads> import> threading> import> time> # counts from 1 to 9> def> func(number):> > for> i> in> range> (> 1> ,> 10> ):> > time.sleep(> 0.01> )> > print> (> 'Thread '> +> str> (number)> +> ': prints '> +> str> (number> *> i))> # creates 3 threads> for> i> in> range> (> 0> ,> 3> ):> > thread> => threading.Thread(target> => func, args> => (i,))> > thread.start()> |
>
>
La funcionalitat del codi anterior també es pot implementar utilitzant el mòdul multiprocessament d'una manera similar, amb molt pocs canvis. Vegeu el codi que es mostra a continuació.
Python 3
# Python program creating> # thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> > for> i> in> range> (> 1> ,> 10> ):> > time.sleep(> 0.01> )> > print> (> 'Processing '> +> str> (number)> +> ': prints '> +> str> (number> *> i))> for> i> in> range> (> 0> ,> 3> ):> > process> => multiprocessing.Process(target> => func, args> => (i,))> > process.start()> |
>
>
Tot i que la interfície dels dos mòduls és similar, els dos mòduls tenen implementacions molt diferents. Tots els fils comparteixen variables globals, mentre que els processos estan completament separats els uns dels altres. Per tant, matar processos és molt més segur en comparació amb matar fils. A la classe Process se li proporciona un mètode, acabar() , matar un procés. Ara, tornant al problema inicial. Suposem que al codi anterior volem matar tots els processos després que hagin passat 0,03 s. Aquesta funcionalitat s'aconsegueix mitjançant el mòdul multiprocessament del codi següent.
Python 3
# Python program killing> # a thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> > for> i> in> range> (> 1> ,> 10> ):> > time.sleep(> 0.01> )> > print> (> 'Processing '> +> str> (number)> +> ': prints '> +> str> (number> *> i))> # list of all processes, so that they can be killed afterwards> all_processes> => []> for> i> in> range> (> 0> ,> 3> ):> > process> => multiprocessing.Process(target> => func, args> => (i,))> > process.start()> > all_processes.append(process)> # kill all processes after 0.03s> time.sleep(> 0.03> )> for> process> in> all_processes:> > process.terminate()> |
>
>
Tot i que els dos mòduls tenen implementacions diferents. Aquesta funcionalitat proporcionada pel mòdul multiprocessament del codi anterior és similar a matar fils. Per tant, el mòdul multiprocessament es pot utilitzar com a senzill alternativa sempre que se'ns demani implementar l'eliminació de fils a Python.
Matar el fil de Python configurant-lo com a dimoni:
Fils de dimoni són aquells fils que s'eliminen quan surt el programa principal. Per exemple
Python 3
java fer mentre exemple
import> threading> import> time> import> sys> def> func():> > while> True> :> > time.sleep(> 0.5> )> > print> (> 'Thread alive, and it won't die on program termination'> )> t1> => threading.Thread(target> => func)> t1.start()> time.sleep(> 2> )> sys.exit()> |
>
>
Tingueu en compte que, el fil t1 es manté viu i impedeix que el programa principal surti mitjançant sys.exit(). A Python, qualsevol fil viu que no sigui un dimoni bloqueja el programa principal per sortir. Mentre que, els fils del dimoni en si es destrueixen tan bon punt surt el programa principal. En altres paraules, tan aviat com surt el programa principal, tots els fils del dimoni s'eliminen. Per declarar un fil com a dimoni, establim l'argument de la paraula clau, daemon com a True. Per exemple, al codi donat, demostra la propietat dels fils del dimoni.
Python 3
# Python program killing> # thread using daemon> import> threading> import> time> import> sys> def> func():> > while> True> :> > time.sleep(> 0.5> )> > print> (> 'Thread alive, but it will die on program termination'> )> t1> => threading.Thread(target> => func)> t1.daemon> => True> t1.start()> time.sleep(> 2> )> sys.exit()> |
>
>
Observeu que, tan aviat com surt el programa principal, el fil t1 s'acaba. Aquest mètode demostra ser extremadament útil en els casos en què la terminació del programa es pot utilitzar per desencadenar l'eliminació de fils. Tingueu en compte que a Python, el programa principal finalitza tan aviat com tots els fils que no són dimonis estan morts, independentment del nombre de fils de dimonis vius. Per tant, els recursos que tenen aquests fils de dimoni, com ara fitxers oberts, transaccions de bases de dades, etc., poden no ser alliberats correctament. El fil inicial de control en un programa Python no és un fil de dimoni. No es recomana matar un fil a la força, tret que se sàpiga amb certesa, que fer-ho no provocarà cap filtració o bloqueig.
Utilitzant una funció oculta _stop():
Per tal de matar un fil, utilitzem la funció oculta _stop() aquesta funció no està documentada, però pot desaparèixer a la següent versió de Python.
el que és 10 d'1 milió
Python 3
# Python program killing> # a thread using ._stop()> # function> import> time> import> threading> class> MyThread(threading.Thread):> > # Thread class with a _stop() method.> > # The thread itself has to check> > # regularly for the stopped() condition.> > def> __init__(> self> ,> *> args,> *> *> kwargs):> > super> (MyThread,> self> ).__init__(> *> args,> *> *> kwargs)> > self> ._stop> => threading.Event()> > # function using _stop function> > def> stop(> self> ):> > self> ._stop.> set> ()> > def> stopped(> self> ):> > return> self> ._stop.isSet()> > def> run(> self> ):> > while> True> :> > if> self> .stopped():> > return> > print> (> 'Hello, world!'> )> > time.sleep(> 1> )> t1> => MyThread()> t1.start()> time.sleep(> 5> )> t1.stop()> t1.join()> |
>
>
Nota: És possible que els mètodes anteriors no funcionin en una situació o una altra, perquè Python no proporciona cap mètode directe per matar fils.