Over het algemeen wordt het abrupt beëindigen van threads als een slechte programmeerpraktijk beschouwd. Als u een thread abrupt beëindigt, kan er een kritieke bron achterblijven die op de juiste manier moet worden gesloten, open. Maar misschien wil je een thread beëindigen zodra een specifieke tijdsperiode is verstreken of een interrupt is gegenereerd. Er zijn verschillende methoden waarmee je een thread in Python kunt doden.
- Uitzonderingen genereren in een Python-thread
- Stopvlag instellen/resetten
- Sporen gebruiken om threads te doden
- De multiprocessing-module gebruiken om threads te doden
- Python-thread doden door deze in te stellen als daemon
- Een verborgen functie gebruiken _stop()
Uitzonderingen opwerpen in een Python-thread:
Deze methode maakt gebruik van de functie PyThreadState_SetAsyncExc() om een uitzondering te maken in de a-thread. Bijvoorbeeld,
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()> |
>
>
Wanneer we de bovenstaande code op een machine uitvoeren en u zult merken dat zodra de functie raise_exception() wordt aangeroepen, de doelfunctie run() eindigt. Dit komt doordat zodra er een uitzondering wordt gegenereerd, de programmabesturing uit het try-blok springt en de functie run() wordt beëindigd. Daarna kan de functie join() worden aangeroepen om de thread te beëindigen. Bij afwezigheid van de functie run_exception(), blijft de doelfunctie run() voor altijd actief en wordt de functie join() nooit aangeroepen om de thread te beëindigen.
Stopvlag instellen/resetten:
Om een thread te beëindigen, kunnen we een stopvlag afkondigen en deze vlag zal af en toe door de thread worden gecontroleerd. Bijvoorbeeld
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'>)> |
>
>
In de bovenstaande code eindigt, zodra de globale variabele stop_threads is ingesteld, de doelfunctie run() en kan de thread t1 worden gedood door t1.join() te gebruiken. Maar om bepaalde redenen kan men afzien van het gebruik van globale variabelen. Voor die situaties kunnen functieobjecten worden doorgegeven om een vergelijkbare functionaliteit te bieden, zoals hieronder weergegeven.
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()> |
>
>
Het functieobject dat in de bovenstaande code wordt doorgegeven, retourneert altijd de waarde van de lokale variabele stop_threads. Deze waarde wordt gecontroleerd in de functie run(), en zodra stop_threads wordt gereset, eindigt de functie run() en kan de thread worden gedood.
Traceringen gebruiken om threads te doden:
Deze methode werkt door te installeren sporen in elke draad. Elk spoor eindigt zichzelf bij de detectie van een stimulus of vlag, waardoor de bijbehorende draad onmiddellijk wordt beëindigd. Bijvoorbeeld
binaire boomtypen
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'>)> |
>
>
In deze code is start() enigszins aangepast om de systeemtraceringfunctie in te stellen met behulp van settrace() . De lokale traceerfunctie is zo gedefinieerd dat, telkens wanneer de kill-vlag (killed) van de betreffende thread wordt ingesteld, er een SystemExit-uitzondering wordt gegenereerd bij de uitvoering van de volgende coderegel, waardoor de uitvoering van de doelfunctie func wordt beëindigd. Nu kan de thread worden gedood met join().
De multiprocessing-module gebruiken om threads te doden:
Met de multiprocessing-module van Python kunt u processen voortbrengen op dezelfde manier waarop u threads voortbrengt met behulp van de threading-module. De interface van de multithreading-module is vergelijkbaar met die van de threading-module. In een bepaalde code hebben we bijvoorbeeld drie threads (processen) gemaakt die tellen van 1 tot 9.
Python3
cast string als int
# 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()> |
>
>
De functionaliteit van de bovenstaande code kan ook worden geïmplementeerd door de multiprocessing-module op een vergelijkbare manier te gebruiken, met zeer weinig wijzigingen. Zie de onderstaande code.
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()> |
>
>
Hoewel de interface van de twee modules vergelijkbaar is, hebben de twee modules zeer verschillende implementaties. Alle threads delen globale variabelen, terwijl processen volledig van elkaar gescheiden zijn. Daarom is het doden van processen veel veiliger in vergelijking met het doden van draden. De Process-klasse krijgt een methode, beëindigen() , om een proces te beëindigen. Nu even terug naar het oorspronkelijke probleem. Stel dat we in de bovenstaande code alle processen willen beëindigen nadat 0,03 seconde is verstreken. Deze functionaliteit wordt bereikt met behulp van de multiprocessing-module in de volgende code.
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()> |
>
>
Hoewel de twee modules verschillende implementaties hebben. Deze functionaliteit van de multiprocessing-module in de bovenstaande code is vergelijkbaar met het doden van threads. Derhalve kan de multiverwerkingsmodule eenvoudig worden gebruikt alternatief wanneer we het doden van threads in Python moeten implementeren.
Python-thread doden door deze in te stellen als daemon:
Daemon-draden zijn de threads die worden gedood wanneer het hoofdprogramma wordt afgesloten. Bijvoorbeeld
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()> |
>
>
Merk op dat thread t1 in leven blijft en verhindert dat het hoofdprogramma wordt afgesloten via sys.exit(). In Python blokkeert elke levende niet-daemon-thread het afsluiten van het hoofdprogramma. Terwijl daemon-threads zelf worden gedood zodra het hoofdprogramma wordt afgesloten. Met andere woorden: zodra het hoofdprogramma wordt afgesloten, worden alle daemon-threads gedood. Om een thread als daemon te declareren, stellen we het trefwoordargument daemon in op True. In de gegeven code demonstreert het bijvoorbeeld de eigenschap van daemon-threads.
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()> |
>
>
Merk op dat zodra het hoofdprogramma wordt afgesloten, de thread t1 wordt gedood. Deze methode blijkt uiterst nuttig te zijn in gevallen waarin programmabeëindiging kan worden gebruikt om het doden van threads te activeren. Merk op dat in Python het hoofdprogramma eindigt zodra alle niet-daemon-threads dood zijn, ongeacht het aantal levende daemon-threads. Het is dus mogelijk dat de bronnen die door deze daemonthreads worden bewaard, zoals geopende bestanden, databasetransacties, enz., niet correct worden vrijgegeven. De initiële besturingsdraad in een Python-programma is geen daemon-thread. Het wordt niet aanbevolen een thread met geweld te beëindigen, tenzij het zeker is dat dit geen lekken of impasses zal veroorzaken.
Een verborgen functie _stop() gebruiken:
Om een thread te beëindigen, gebruiken we de verborgen functie _stop(). Deze functie is niet gedocumenteerd, maar zou in de volgende versie van Python kunnen verdwijnen.
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()> |
vb en vb net
>
>
Opmerking: Bovenstaande methoden werken mogelijk niet in een of andere situatie, omdat Python geen directe methode biedt om threads te beëindigen.