Vo všeobecnosti sa náhle zabíjanie vlákien považuje za zlú programovaciu prax. Náhle zabitie vlákna môže zanechať kritický zdroj, ktorý musí byť správne uzavretý, otvorený. Ale možno budete chcieť zabiť vlákno po uplynutí určitého časového obdobia alebo po vygenerovaní nejakého prerušenia. Existujú rôzne metódy, ktorými môžete zabiť vlákno v pythone.
- Zvyšovanie výnimiek vo vlákne python
- Nastaviť/resetovať príznak zastavenia
- Použitie stôp na zabíjanie vlákien
- Použitie modulu multiprocessingu na zabíjanie vlákien
- Zabitie vlákna Pythonu jeho nastavením ako démona
- Použitie skrytej funkcie _stop()
Vyvolanie výnimiek vo vlákne pythonu:
Táto metóda využíva funkciu PyThreadState_SetAsyncExc() vyvolať výnimku vo vlákne. Napríklad,
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()> |
>
>
Keď spustíme vyššie uvedený kód v počítači a všimnete si, že hneď ako sa zavolá funkcia raise_exception(), cieľová funkcia run() skončí. Je to preto, že akonáhle je vyvolaná výnimka, riadenie programu vyskočí z bloku try a funkcia run() sa ukončí. Potom je možné zavolať funkciu join() na zabitie vlákna. Pri absencii funkcie run_exception() je cieľová funkcia run() spustená navždy a funkcia join() sa nikdy nezavolá, aby zabila vlákno.
Nastaviť/resetovať príznak zastavenia:
Aby sme zabili vlákna, môžeme vyhlásiť stop príznak a tento príznak bude vlákno občas kontrolovať. Napríklad
java previesť znak na reťazec
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'>)> |
>
>
Vo vyššie uvedenom kóde, akonáhle je nastavená globálna premenná stop_threads, cieľová funkcia run() končí a vlákno t1 môže byť zabité pomocou t1.join(). Z určitých dôvodov však možno upustiť od používania globálnej premennej. V takýchto situáciách je možné odovzdať funkčné objekty, aby poskytli podobnú funkčnosť, ako je uvedené nižšie.
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()> |
>
stdin v c
>
Objekt funkcie odovzdaný vo vyššie uvedenom kóde vždy vráti hodnotu lokálnej premennej stop_threads. Táto hodnota sa kontroluje vo funkcii run() a akonáhle sa stop_threads resetuje, funkcia run() sa skončí a vlákno môže byť zabité.
Použitie stôp na zabíjanie vlákien:
Táto metóda funguje inštaláciou stopy v každom vlákne. Každá stopa sa ukončí pri detekcii nejakého podnetu alebo príznaku, čím sa okamžite zabije súvisiace vlákno. Napríklad
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'>)> |
>
>
V tomto kóde je start() mierne upravený tak, aby nastavil funkciu sledovania systému pomocou settrace() . Funkcia lokálneho sledovania je definovaná tak, že vždy, keď je nastavený príznak zabitia (killed) príslušného vlákna, pri spustení ďalšieho riadku kódu sa vyvolá výnimka SystemExit, ktorá ukončí vykonávanie cieľovej funkcie func. Teraz môže byť vlákno zabité pomocou join().
Použitie modulu multiprocessingu na zabíjanie vlákien:
Multiprocessingový modul Pythonu vám umožňuje vytvárať procesy podobným spôsobom, akým vytvárate vlákna pomocou modulu na vytváranie vlákien. Rozhranie modulu s viacerými vláknami je podobné ako rozhranie modulu na vytváranie vlákien. Napríklad v danom kóde sme vytvorili tri vlákna (procesy), ktoré sa počítajú od 1 do 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()> |
>
>
Funkcionalitu vyššie uvedeného kódu je možné implementovať aj použitím modulu multiprocessingu podobným spôsobom s veľmi malými zmenami. Pozrite si kód uvedený nižšie.
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()> |
uložiť video z youtube vlc
>
>
Aj keď je rozhranie týchto dvoch modulov podobné, tieto dva moduly majú veľmi odlišné implementácie. Všetky vlákna zdieľajú globálne premenné, zatiaľ čo procesy sú od seba úplne oddelené. Proces zabíjania je teda oveľa bezpečnejší v porovnaní so zabíjaním vlákien. Trieda Process poskytuje metódu, ukončiť() , zabiť proces. Teraz sa vráťme k pôvodnému problému. Predpokladajme, že vo vyššie uvedenom kóde chceme zabiť všetky procesy po uplynutí 0,03 s. Táto funkcionalita je dosiahnutá pomocou modulu multiprocessingu v nasledujúcom kóde.
ako previesť reťazec na int java
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()> |
>
>
Aj keď tieto dva moduly majú rôzne implementácie. Táto funkcia poskytovaná modulom multiprocessingu vo vyššie uvedenom kóde je podobná zabíjaniu vlákien. Preto je možné modul multiprocessingu použiť ako jednoduchý alternatíva vždy, keď sa od nás vyžaduje implementácia zabíjania vlákien v Pythone.
Zabitie vlákna Pythonu jeho nastavením ako démona:
Vlákna démonov sú vlákna, ktoré sú zabité pri ukončení hlavného programu. Napríklad
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()> |
>
>
Všimnite si, že vlákno t1 zostáva nažive a bráni hlavnému programu ukončiť cez sys.exit(). V Pythone každé živé vlákno, ktoré nie je démonom, blokuje hlavný program na ukončenie. Zatiaľ čo samotné vlákna démonov sú zabité hneď po ukončení hlavného programu. Inými slovami, akonáhle sa hlavný program ukončí, všetky vlákna démona sa zastavia. Ak chcete vlákno deklarovať ako démona, nastavíme kľúčové slovo argument, daemon ako True. Napríklad v danom kóde demonštruje vlastnosť démonových vlákien.
Python3
zoznam triediť podľa java
# 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()> |
>
>
Všimnite si, že akonáhle sa hlavný program ukončí, vlákno t1 je zabité. Táto metóda sa ukazuje ako mimoriadne užitočná v prípadoch, keď je možné použiť ukončenie programu na spustenie zabíjania vlákien. Všimnite si, že v Pythone sa hlavný program ukončí, akonáhle sú všetky vlákna, ktoré nie sú démonmi, mŕtve, bez ohľadu na počet živých vlákien démona. Prostriedky držané týmito vláknami démonov, ako sú otvorené súbory, databázové transakcie atď., sa preto nemusia správne uvoľniť. Počiatočné vlákno kontroly v programe python nie je vlákno démona. Násilné zabíjanie vlákna sa neodporúča, pokiaľ nie je s istotou známe, že to nespôsobí žiadne úniky alebo uviaznutie.
Použitie skrytej funkcie _stop() :
Aby sme zabili vlákno, používame skrytú funkciu _stop(), táto funkcia nie je zdokumentovaná, ale môže zmiznúť v ďalšej verzii pythonu.
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()> |
>
>
Poznámka: Vyššie uvedené metódy nemusia v určitej situácii fungovať, pretože python neposkytuje žiadnu priamu metódu na zabíjanie vlákien.