logo

Python | Forskellige måder at dræbe en tråd på

Generelt betragtes det som en dårlig programmeringspraksis at dræbe tråde brat. At dræbe en tråd brat kan efterlade en kritisk ressource, der skal lukkes korrekt, åben. Men du vil måske dræbe en tråd, når en bestemt tidsperiode er gået, eller et afbrydelse er blevet genereret. Der er de forskellige metoder, hvormed du kan dræbe en tråd i python.

  • At rejse undtagelser i en python-tråd
  • Indstil/nulstil stopflag
  • Brug af spor til at dræbe tråde
  • Brug af multiprocessing-modulet til at dræbe tråde
  • Dræber Python-tråden ved at sætte den som dæmon
  • Brug af en skjult funktion _stop()

At rejse undtagelser i en python-tråd:
Denne metode bruger funktionen PyThreadState_SetAsyncExc() at rejse en undtagelse i en tråd. For eksempel,



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

>

>

Når vi kører koden ovenfor i en maskine, og du vil bemærke, så snart funktionen raise_exception() kaldes, slutter målfunktionen run(). Dette skyldes, at så snart en undtagelse er rejst, springer programstyringen ud af try-blokken, og run()-funktionen afsluttes. Derefter kan join()-funktionen kaldes for at dræbe tråden. I mangel af funktionen run_exception(), bliver målfunktionen run() ved med at køre for evigt, og join()-funktionen kaldes aldrig for at dræbe tråden.

Indstil/nulstil stopflag:
For at dræbe en tråd kan vi erklære et stopflag, og dette flag vil af og til blive kontrolleret af tråden. For eksempel

Python3




forårsstøvlearkitektur
# 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'>)>

>

>

I ovenstående kode, så snart den globale variabel stop_threads er indstillet, slutter målfunktionen run() og tråden t1 kan dræbes ved at bruge t1.join(). Men man kan afholde sig fra at bruge global variabel på grund af visse årsager. I disse situationer kan funktionsobjekter sendes for at give en lignende funktionalitet som vist nedenfor.

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

>

>

Funktionsobjektet, der sendes i ovenstående kode, returnerer altid værdien af ​​den lokale variabel stop_threads. Denne værdi kontrolleres i funktionen run(), og så snart stop_threads er nulstillet, slutter run()-funktionen, og tråden kan dræbes.

Brug af spor til at dræbe tråde:
Denne metode fungerer ved at installere spor i hver tråd. Hvert spor afsluttes af sig selv ved detektering af et eller andet stimulus eller flag og dræber således øjeblikkeligt den tilknyttede tråd. For eksempel

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

>

>

I denne kode er start() lidt ændret for at indstille systemsporingsfunktionen ved hjælp af settrace() . Den lokale sporingsfunktion er defineret sådan, at når kill-flaget (dræbt) for den respektive tråd er sat, opstår der en SystemExit-undtagelse ved udførelse af den næste kodelinje, som afslutter udførelsen af ​​målfunktionen func. Nu kan tråden dræbes med join().

Brug af multiprocessing-modulet til at dræbe tråde:
Multiprocessing-modulet i Python giver dig mulighed for at spawn processer på samme måde, som du spawner tråde ved hjælp af threading-modulet. Grænsefladen for multithreading-modulet svarer til gevindmodulets grænseflade. For eksempel oprettede vi i en given kode tre tråde (processer), som tæller fra 1 til 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()>

>

>

Funktionaliteten af ​​ovenstående kode kan også implementeres ved at bruge multiprocessing-modulet på en lignende måde, med meget få ændringer. Se koden nedenfor.

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

>

>

Selvom grænsefladen mellem de to moduler er ens, har de to moduler meget forskellige implementeringer. Alle tråde deler globale variabler, hvorimod processer er fuldstændig adskilte fra hinanden. Derfor er drabsprocesser meget sikrere sammenlignet med at dræbe tråde. Process-klassen leveres med en metode, opsige() , for at dræbe en proces. Nu tilbage til det oprindelige problem. Antag, at vi i ovenstående kode ønsker at dræbe alle processerne, efter at 0.03s er gået. Denne funktionalitet opnås ved hjælp af multiprocessing-modulet i følgende kode.

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

>

>

Selvom de to moduler har forskellige implementeringer. Denne funktionalitet leveret af multiprocessing-modulet i ovenstående kode svarer til at dræbe tråde. Derfor kan multiprocessing-modulet bruges som et simpelt alternativ hver gang vi er forpligtet til at implementere dræbningen af ​​tråde i Python.

Dræber Python-tråden ved at sætte den som dæmon:
Dæmon tråde er de tråde, der bliver dræbt, når hovedprogrammet afsluttes. For eksempel

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

>

>

Bemærk, at tråd t1 forbliver i live og forhindrer hovedprogrammet i at afslutte via sys.exit(). I Python blokerer enhver levende tråd, der ikke er dæmon, hovedprogrammet for at afslutte. Mens dæmontrådene selv bliver dræbt, så snart hovedprogrammet afsluttes. Med andre ord, så snart hovedprogrammet afsluttes, dræbes alle dæmontrådene. For at erklære en tråd som dæmon sætter vi søgeordsargumentet dæmon som Sand. For eksempel i den givne kode demonstrerer den egenskaben af ​​daemon-tråde.

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

>

>

Bemærk, at så snart hovedprogrammet afsluttes, afbrydes tråden t1. Denne metode viser sig at være yderst nyttig i tilfælde, hvor programafslutning kan bruges til at udløse dræbning af tråde. Bemærk, at i Python afsluttes hovedprogrammet, så snart alle ikke-dæmontråde er døde, uanset antallet af levende dæmontråde. Derfor kan ressourcerne i disse dæmontråde, såsom åbne filer, databasetransaktioner osv. muligvis ikke frigives korrekt. Den indledende kontroltråd i et python-program er ikke en dæmontråd. Det anbefales ikke at dræbe en tråd med magt, medmindre det med sikkerhed vides, at det ikke vil forårsage lækager eller dødvande.
Brug af en skjult funktion _stop():
For at dræbe en tråd bruger vi skjult funktion _stop() denne funktion er ikke dokumenteret, men kan forsvinde i den næste version af python.

Python3




# 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()>

>

>

Bemærk: Ovenstående metoder virker muligvis ikke i en eller anden situation, fordi python ikke giver nogen direkte metode til at dræbe tråde.