logo

Python | Ulike måter å drepe en tråd på

Generelt sett anses å drepe tråder brått som en dårlig programmeringspraksis. Å drepe en tråd brått kan etterlate en kritisk ressurs som må lukkes ordentlig, åpen. Men du vil kanskje drepe en tråd når en bestemt tidsperiode har gått eller et avbrudd har blitt generert. Det er forskjellige metoder for å drepe en tråd i python.

  • Tar opp unntak i en pyton-tråd
  • Sett/tilbakestill stoppflagg
  • Bruke spor for å drepe tråder
  • Bruke multiprosesseringsmodulen for å drepe tråder
  • Drep Python-tråden ved å sette den som demon
  • Bruke en skjult funksjon _stop()

Tar opp unntak i en pyton-tråd:
Denne metoden bruker funksjonen PyThreadState_SetAsyncExc() å ta opp et unntak 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 kjører koden ovenfor i en maskin og du vil legge merke til, så snart funksjonen raise_exception() kalles, avsluttes målfunksjonen run(). Dette er fordi så snart et unntak oppstår, hopper programkontrollen ut av try-blokken og run()-funksjonen avsluttes. Etter det kan join()-funksjonen kalles for å drepe tråden. I fravær av funksjonen run_exception(), fortsetter målfunksjonen run() å kjøre for alltid, og join()-funksjonen kalles aldri for å drepe tråden.

Sett/tilbakestill stoppflagg:
For å drepe en tråd, kan vi erklære et stoppflagg og dette flagget vil bli sjekket av og til av tråden. For eksempel

Python3




innsettingsnøkkel for laptop
# 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 koden ovenfor, så snart den globale variabelen stop_threads er satt, slutter målfunksjonen run() og tråden t1 kan drepes ved å bruke t1.join(). Men man kan avstå fra å bruke global variabel på grunn av visse årsaker. For slike situasjoner kan funksjonsobjekter sendes for å gi en lignende funksjonalitet 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()>

>

>

Funksjonsobjektet som sendes i koden ovenfor, returnerer alltid verdien til den lokale variabelen stop_threads. Denne verdien sjekkes i funksjonen run(), og så snart stop_threads er tilbakestilt, avsluttes run()-funksjonen og tråden kan drepes.

Bruke spor for å drepe tråder:
Denne metoden fungerer ved å installere spor i hver tråd. Hvert spor avsluttes av seg selv ved deteksjon av en stimulus eller flagg, og dreper dermed den tilknyttede tråden umiddelbart. 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 koden er start() litt modifisert for å angi systemsporingsfunksjonen ved hjelp av settrace() . Den lokale sporingsfunksjonen er definert slik at hver gang kill-flagget (killed) til den respektive tråden settes, oppstår et SystemExit-unntak ved kjøring av neste kodelinje, som avslutter kjøringen av målfunksjonen func. Nå kan tråden drepes med join().

Bruke multiprosesseringsmodulen for å drepe tråder:
Multiprosesseringsmodulen til Python lar deg lage prosesser på samme måte som du lager tråder ved å bruke trådmodulen. Grensesnittet til flertrådingsmodulen er likt det til gjengemodulen. For eksempel, i en gitt kode opprettet vi tre tråder (prosesser) som teller 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()>

>

>

Funksjonaliteten til koden ovenfor kan også implementeres ved å bruke multiprosesseringsmodulen på lignende måte, med svært få endringer. Se koden gitt 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()>

>

>

Selv om grensesnittet til de to modulene er likt, har de to modulene svært forskjellige implementeringer. Alle trådene deler globale variabler, mens prosesser er helt atskilt fra hverandre. Derfor er drapsprosesser mye tryggere sammenlignet med å drepe tråder. Process-klassen er gitt en metode, terminere() , for å drepe en prosess. Nå, tilbake til det første problemet. Anta at vi i koden ovenfor ønsker å drepe alle prosessene etter at 0.03s har passert. Denne funksjonaliteten oppnås ved å bruke multiprosesseringsmodulen 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()>

>

>

Selv om de to modulene har forskjellige implementeringer. Denne funksjonaliteten levert av multiprosesseringsmodulen i koden ovenfor ligner på å drepe tråder. Derfor kan multiprosesseringsmodulen brukes som en enkel alternativ når vi er pålagt å implementere dreping av tråder i Python.

Drep Python-tråden ved å sette den som daemon:
Demon-tråder er de trådene som blir drept når hovedprogrammet avsluttes. 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()>

>

>

Legg merke til at tråden t1 forblir i live og hindrer hovedprogrammet i å avslutte via sys.exit(). I Python blokkerer enhver levende ikke-daemon-tråd hovedprogrammet for å avslutte. Mens demon-trådene selv blir drept så snart hovedprogrammet avsluttes. Med andre ord, så snart hovedprogrammet avsluttes, blir alle daemon-trådene drept. For å erklære en tråd som daemon, setter vi søkeordargumentet, daemon som True. For eksempel i den gitte koden demonstrerer den egenskapen til daemon-tråder.

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

>

>

Legg merke til at så snart hovedprogrammet avsluttes, blir tråden t1 drept. Denne metoden viser seg å være ekstremt nyttig i tilfeller der programavslutning kan brukes til å utløse dreping av tråder. Merk at i Python avsluttes hovedprogrammet så snart alle ikke-daemon-trådene er døde, uavhengig av antall demon-tråder i live. Derfor kan det hende at ressursene som holdes av disse daemon-trådene, slik som åpne filer, databasetransaksjoner, etc. ikke blir utgitt på riktig måte. Den første kontrolltråden i et python-program er ikke en demon-tråd. Å drepe en tråd med makt anbefales ikke med mindre det er sikkert kjent at dette ikke vil føre til lekkasjer eller vranglås.
Bruke en skjult funksjon _stop():
For å drepe en tråd bruker vi skjult funksjon _stop() denne funksjonen er ikke dokumentert, men kan forsvinne i neste versjon av 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()>

>

>

Merk: Metodene ovenfor fungerer kanskje ikke i en eller annen situasjon, fordi python ikke gir noen direkte metode for å drepe tråder.