Yleensä säikeiden äkillistä tappamista pidetään huonona ohjelmointikäytäntönä. Säikeen äkillinen lopettaminen saattaa jättää kriittisen resurssin, joka on suljettava kunnolla, auki. Mutta saatat haluta lopettaa säikeen, kun tietty ajanjakso on kulunut tai jokin keskeytys on luotu. Pythonissa on useita menetelmiä, joilla voit tappaa säiettä.
- Poikkeusten nostaminen python-säikeessä
- Aseta/nollaa pysäytyslippu
- Jälkien käyttäminen lankojen tappamiseen
- Monikäsittelymoduulin käyttäminen säikeiden lopettamiseen
- Python-säikeen lopettaminen asettamalla se demoniksi
- Piilotetun funktion _stop() käyttäminen
Poikkeusten nostaminen python-säikeessä:
Tämä menetelmä käyttää funktiota PyThreadState_SetAsyncExc() herättääksesi poikkeuksen a-ketjussa. Esimerkiksi,
Python 3
# 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()> |
>
>
Kun suoritamme yllä olevan koodin koneessa ja huomaat, että heti kun funktio raise_exception() kutsutaan, kohdefunktio run() päättyy. Tämä johtuu siitä, että heti kun poikkeus nostetaan esiin, ohjelman ohjaus hyppää ulos try-lohkosta ja run() -toiminto lopetetaan. Tämän jälkeen voidaan kutsua join()-funktio lopettamaan säiettä. Jos funktiota run_exception() ei ole, kohdefunktio run() pysyy käynnissä ikuisesti ja join()-funktiota ei koskaan kutsuta lopettamaan säiettä.
Aseta/nollaa pysäytyslippu:
Voit lopettaa säikeen, voimme julistaa stop-lipun, ja tämä lippu tarkistetaan silloin tällöin. Esimerkiksi
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'>)> |
>
on suhde
>
Yllä olevassa koodissa, heti kun globaali muuttuja stop_threads on asetettu, kohdefunktio run() päättyy ja säie t1 voidaan lopettaa komennolla t1.join(). Globaalimuuttujaa voidaan kuitenkin jättää käyttämättä tietyistä syistä. Tällaisissa tilanteissa funktioobjekteja voidaan välittää samanlaisen toiminnallisuuden aikaansaamiseksi, kuten alla on esitetty.
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()> |
>
>
Yllä olevassa koodissa välitetty funktioolio palauttaa aina paikallisen muuttujan stop_threads arvon. Tämä arvo tarkistetaan funktiossa run(), ja heti kun stop_threads nollataan, run()-funktio päättyy ja säie voidaan lopettaa.
Jälkien käyttäminen lankojen tappamiseen:
Tämä menetelmä toimii asentamalla jälkiä jokaisessa langassa. Jokainen jälki päättyy jonkin ärsykkeen tai lipun havaitsemiseen, mikä tappaa välittömästi siihen liittyvän säikeen. Esimerkiksi
Python 3
ero rakkauden ja tykkäämisen välillä
# 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'>)> |
>
>
Tässä koodissa start() on hieman muokattu asettamaan järjestelmän jäljitysfunktio käyttämällä settrace() . Paikallinen jäljitystoiminto määritellään siten, että aina kun vastaavan säikeen kill-lippu (killed) asetetaan, SystemExit-poikkeus nostetaan seuraavan koodirivin suorittamisen yhteydessä, mikä lopettaa kohdefunktion funktion suorittamisen. Nyt säie voidaan lopettaa join()-komennolla.
Monikäsittelymoduulin käyttäminen säikeiden lopettamiseen:
Pythonin moniprosessointimoduulin avulla voit synnyttää prosesseja samalla tavalla kuin säikeitä ketjutusmoduulin avulla. Monisäikeistysmoduulin käyttöliittymä on samanlainen kuin kierteitysmoduulin. Esimerkiksi annetussa koodissa loimme kolme säiettä (prosessia), jotka laskevat 1:stä 9:ään.
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()> |
>
>
Yllä olevan koodin toiminnallisuus voidaan toteuttaa myös käyttämällä moniprosessointimoduulia samalla tavalla, hyvin pienin muutoksin. Katso alla oleva koodi.
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()> |
>
>
Vaikka kahden moduulin käyttöliittymä on samanlainen, molemmilla moduuleilla on hyvin erilaiset toteutukset. Kaikki säikeet jakavat globaaleja muuttujia, kun taas prosessit ovat täysin erillisiä toisistaan. Näin ollen tappamisprosessit ovat paljon turvallisempia kuin tapposäikeet. Prosessi-luokka tarjoaa menetelmän, lopettaa() , tappaa prosessi. Nyt takaisin alkuperäiseen ongelmaan. Oletetaan, että yllä olevassa koodissa haluamme tappaa kaikki prosessit 0,03 sekunnin kuluttua. Tämä toiminnallisuus saavutetaan käyttämällä moniprosessointimoduulia seuraavassa koodissa.
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()> |
>
>
Vaikka kahdella moduulilla on erilaiset toteutukset. Tämä yllä olevan koodin moniprosessointimoduulin tarjoama toiminto on samanlainen kuin säikeiden tappaminen. Näin ollen moniprosessointimoduulia voidaan käyttää yksinkertaisena vaihtoehto aina kun meitä vaaditaan toteuttamaan säikeiden tappaminen Pythonissa.
Python-säikeen lopettaminen asettamalla se demoniksi:
Daemon säikeet ovat ne säikeet, jotka lopetetaan pääohjelman sulkeuduttua. Esimerkiksi
Python 3
mikä on pino javassa
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()> |
>
>
Huomaa, että säie t1 pysyy hengissä ja estää pääohjelmaa poistumasta sys.exit(:n) kautta. Pythonissa mikä tahansa elävä ei-daemon-säie estää pääohjelman poistumisen. Sitä vastoin itse daemon-säikeet kuolevat heti, kun pääohjelma poistuu. Toisin sanoen, heti kun pääohjelma poistuu, kaikki demonin säikeet tapetaan. Jos haluat julistaa säikeen daemoniksi, asetamme avainsana-argumentin daemon arvoksi True. Esimerkiksi annetussa koodissa se osoittaa demoniketjujen ominaisuuden.
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()> |
>
>
Huomaa, että heti kun pääohjelma poistuu, säie t1 lopetetaan. Tämä menetelmä osoittautuu erittäin hyödylliseksi tapauksissa, joissa ohjelman lopettamista voidaan käyttää säikeiden tappamisen laukaisemiseen. Huomaa, että Pythonissa pääohjelma päättyy heti, kun kaikki ei-daemon-säikeet ovat kuolleet, riippumatta elossa olevien daemon-säikeiden määrästä. Tästä syystä näiden daemon-säikeiden hallussa olevia resursseja, kuten avoimia tiedostoja, tietokantatapahtumia jne., ei ehkä vapauteta oikein. Python-ohjelman ensimmäinen ohjaussäie ei ole demon-säie. Langan väkisin lopettamista ei suositella, ellei ole varmaa tietoa, että se ei aiheuta vuotoja tai umpikujaa.
Piilotetun funktion _stop() käyttäminen:
Säikeen lopettamiseksi käytämme piilotettua funktiota _stop() tätä funktiota ei ole dokumentoitu, mutta se saattaa kadota pythonin seuraavassa versiossa.
string.valueof
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()> |
>
>
Huomautus: Yllä olevat menetelmät eivät välttämättä toimi joissakin tilanteissa, koska python ei tarjoa suoraa menetelmää säikeiden tappamiseen.