În general, uciderea bruscă a firelor este considerată o practică proastă de programare. Omoarea bruscă a unui fir poate lăsa o resursă critică care trebuie închisă corect, deschisă. Dar este posibil să doriți să opriți un fir de execuție odată ce a trecut o anumită perioadă de timp sau a fost generată o întrerupere. Există diferite metode prin care puteți ucide un fir în Python.
- Ridicarea de excepții într-un fir python
- Setați/Resetați steag de oprire
- Folosind urme pentru a ucide firele
- Folosind modulul de multiprocesare pentru a elimina firele
- Omorârea firului Python setându-l ca demon
- Folosind o funcție ascunsă _stop()
Ridicarea de excepții într-un fir python:
Această metodă folosește funcția PyThreadState_SetAsyncExc() pentru a ridica o excepție în firul a. De exemplu,
Python3
# 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>>>> >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()> |
>
>
Când rulăm codul de mai sus într-o mașină și veți observa, de îndată ce funcția raise_exception() este apelată, funcția țintă run() se termină. Acest lucru se datorează faptului că de îndată ce o excepție este ridicată, controlul programului iese din blocul try și funcția run() este terminată. După aceea, funcția join() poate fi apelată pentru a ucide firul. În absența funcției run_exception(), funcția țintă run() continuă să ruleze pentru totdeauna și funcția join() nu este apelată niciodată pentru a ucide firul.
Setare/Resetare steag de oprire:
Pentru a distruge un fir de execuție, putem declara un steag de oprire și acest flag va fi verificat ocazional de către fir. De exemplu
Python3
# 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'>)> |
>
cum se convertesc din int în șir în java
>
În codul de mai sus, de îndată ce variabila globală stop_threads este setată, funcția țintă run() se termină și firul t1 poate fi oprit folosind t1.join(). Dar se poate abține de la utilizarea variabilei globale din anumite motive. Pentru aceste situații, obiectele funcție pot fi transmise pentru a oferi o funcționalitate similară așa cum se arată mai jos.
Python3
# 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()> |
>
diferența dintre dragoste și placere
>
Obiectul funcție transmis în codul de mai sus returnează întotdeauna valoarea variabilei locale stop_threads. Această valoare este verificată în funcția run() și de îndată ce stop_threads este resetat, funcția run() se termină și firul poate fi oprit.
Folosind urme pentru a ucide firele:
Această metodă funcționează prin instalare urme în fiecare fir. Fiecare urmă se termină la detectarea unui stimul sau steag, ucigând astfel instantaneu firul asociat. De exemplu
Python3
# 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'>)> |
>
>
În acest cod, start() este ușor modificat pentru a seta funcția de urmărire a sistemului folosind settrace() . Funcția de urmărire locală este definită astfel încât, ori de câte ori este setat indicatorul kill (killed) al firului de execuție respectiv, o excepție SystemExit este ridicată la executarea următoarei linii de cod, care încheie execuția funcției țintă. Acum firul poate fi ucis cu join().
Folosind modulul de multiprocesare pentru a ucide firele de execuție:
Modulul de multiprocesare din Python vă permite să generați procese în același mod în care generați fire de execuție folosind modulul de threading. Interfața modulului multithreading este similară cu cea a modulului threading. De exemplu, într-un anumit cod am creat trei fire (procese) care numără de la 1 la 9.
Python3
# 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()> |
>
>
Funcționalitatea codului de mai sus poate fi implementată și prin utilizarea modulului de multiprocesare într-o manieră similară, cu foarte puține modificări. Vezi codul dat mai jos.
Python3
# 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()> |
Jasmine Davis în copilărie
>
>
Deși interfața celor două module este similară, cele două module au implementări foarte diferite. Toate firele de execuție partajează variabile globale, în timp ce procesele sunt complet separate unele de altele. Prin urmare, uciderea proceselor este mult mai sigură în comparație cu uciderea firelor. Clasei Process este furnizată o metodă, termina () , a ucide un proces. Acum, revenind la problema inițială. Să presupunem că, în codul de mai sus, dorim să omorâm toate procesele după ce au trecut 0,03 secunde. Această funcționalitate este realizată folosind modulul de multiprocesare din următorul cod.
vulpe vs lup
Python3
# 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()> |
>
>
Deși cele două module au implementări diferite. Această funcționalitate oferită de modulul de multiprocesare din codul de mai sus este similară cu uciderea firelor de execuție. Prin urmare, modulul de multiprocesare poate fi utilizat ca simplu alternativă ori de câte ori ni se cere să implementăm uciderea firelor în Python.
Omorârea firului Python setându-l ca demon:
Fire Daemon sunt acele fire care sunt eliminate la ieșirea programului principal. De exemplu
Python3
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()> |
>
>
Observați că firul t1 rămâne în viață și împiedică ieșirea programului principal prin sys.exit(). În Python, orice fir viu non-demon blochează programul principal pentru a ieși. Întrucât, firele de demon în sine sunt distruse de îndată ce programul principal iese. Cu alte cuvinte, de îndată ce programul principal iese, toate firele de demon sunt eliminate. Pentru a declara un fir ca daemon, setăm argumentul cheie, daemon ca True. De exemplu, în codul dat, demonstrează proprietatea firelor de demon.
Python3
# 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()> |
>
>
Observați că, de îndată ce programul principal iese, firul t1 este oprit. Această metodă se dovedește a fi extrem de utilă în cazurile în care terminarea programului poate fi folosită pentru a declanșa uciderea firelor de execuție. Rețineți că în Python, programul principal se termină de îndată ce toate firele non-daemon sunt moarte, indiferent de numărul de fire de demon în viață. Prin urmare, resursele deținute de aceste fire de demon, cum ar fi fișierele deschise, tranzacțiile cu baze de date etc., pot să nu fie eliberate corect. Firul inițial de control într-un program python nu este un fir de demon. Uciderea forțată a unui fir nu este recomandată decât dacă se știe cu siguranță că acest lucru nu va provoca scurgeri sau blocaje.
Folosind o funcție ascunsă _stop() :
Pentru a elimina un fir, folosim funcția ascunsă _stop() această funcție nu este documentată, dar ar putea dispărea în următoarea versiune de python.
Python3
listă java
# 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()> |
>
>
Notă: Metodele de mai sus ar putea să nu funcționeze într-o situație sau alta, deoarece python nu oferă nicio metodă directă de a ucide firele.