Czy jest jakiś sposób, aby zabić nić?
Czy można zakończyć uruchomiony wątek bez ustawiania / sprawdzania FLAG / semaforów / itd.?
28 answers
Ogólnie jest złym wzorcem, aby nagle zabić wątek, w Pythonie i w dowolnym języku. Pomyśl o następujących przypadkach:
- wątek przechowuje krytyczny zasób, który musi być poprawnie zamknięty
- wątek stworzył kilka innych wątków, które również muszą zostać zabite.
Dobrym sposobem obsługi tego, jeśli możesz sobie na to pozwolić (jeśli zarządzasz własnymi wątkami), jest posiadanie znacznika exit_request, że każdy wątek sprawdza regularny interwał, aby sprawdzić, czy czas na wyjście.
Na przykład:
import threading
class StoppableThread(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(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
W tym kodzie powinieneś wywołać stop()
w wątku, gdy chcesz go zakończyć, i poczekać, aż wątek zakończy się prawidłowo używając join()
. Wątek powinien sprawdzać znacznik stop w regularnych odstępach czasu.
Są jednak przypadki, kiedy naprawdę trzeba zabić wątek. Przykładem jest zawijanie zewnętrznej biblioteki, która jest zajęta przez długie połączenia i chcesz ją przerwać.
Poniższy kod pozwala (z niektóre ograniczenia), aby podnieść wyjątek w wątku Pythona:
def _async_raise(tid, exctype):
'''Raises an exception in the threads with id tid'''
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# "if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), None)
raise SystemError("PyThreadState_SetAsyncExc failed")
class ThreadWithExc(threading.Thread):
'''A thread class that supports raising an exception in the thread from
another thread.
'''
def _get_my_tid(self):
"""determines this (self's) thread id
CAREFUL: this function is executed in the context of the caller
thread, to get the identity of the thread represented by this
instance.
"""
if not self.isAlive():
raise threading.ThreadError("the thread is not active")
# do we have it cached?
if hasattr(self, "_thread_id"):
return self._thread_id
# no, look for it in the _active dict
for tid, tobj in threading._active.items():
if tobj is self:
self._thread_id = tid
return tid
# TODO: in python 2.6, there's a simpler way to do: self.ident
raise AssertionError("could not determine the thread's id")
def raiseExc(self, exctype):
"""Raises the given exception type in the context of this thread.
If the thread is busy in a system call (time.sleep(),
socket.accept(), ...), the exception is simply ignored.
If you are sure that your exception should terminate the thread,
one way to ensure that it works is:
t = ThreadWithExc( ... )
...
t.raiseExc( SomeException )
while t.isAlive():
time.sleep( 0.1 )
t.raiseExc( SomeException )
If the exception is to be caught by the thread, you need a way to
check that your thread has caught it.
CAREFUL: this function is executed in the context of the
caller thread, to raise an exception in the context of the
thread represented by this instance.
"""
_async_raise( self._get_my_tid(), exctype )
(na podstawie Killable Threads by Tomer Filiba. Cytat o zwracanej wartości PyThreadState_SetAsyncExc
wydaje się pochodzić ze starej wersji Pythona .)
Jak wspomniano w dokumentacji, nie jest to magiczna kula, ponieważ jeśli wątek jest zajęty poza interpreterem Pythona, nie wychwytuje przerwania.
Dobrym wzorcem użycia tego kodu jest to, aby wątek złapał konkretny wyjątek i wykonaj sprzątanie. W ten sposób możesz przerwać zadanie i nadal mieć odpowiednie sprzątanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-09 14:25:00
Nie ma oficjalnego API, aby to zrobić, nie.
Musisz użyć platform API, aby zabić wątek, np. pthread_kill, lub TerminateThread. Możesz uzyskać dostęp do takiego API np. przez pythonwin lub przez ctypes.
Zauważ, że jest to z natury niebezpieczne. Prawdopodobnie doprowadzi to do nieoczyszczalnych śmieci (od lokalnych zmiennych ramek stosu, które stają się śmieciami) i może prowadzić do blokad, jeśli wątek zabity ma GIL w momencie jego zabicia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 15:08:07
A multiprocessing.Process
can p.terminate()
W przypadkach, gdy chcę zabić wątek, ale nie chcę używać FLAG/blokad/sygnałów / semaforów/zdarzeń / cokolwiek, promuję wątki do pełnych procesów. Dla kodu, który wykorzystuje tylko kilka wątków, narzut nie jest taki zły.
Np. jest to przydatne do łatwego zakończenia "wątków" pomocniczych, które wykonują blokowanie We / Wy
Konwersja jest trywialna: w powiązanym kodzie Zamień wszystkie threading.Thread
na multiprocessing.Process
i wszystkie queue.Queue
z multiprocessing.Queue
i dodaj wymagane wywołania p.terminate()
do procesu rodzica, który chce zabić swoje dziecko p
Zobacz dokumentację Pythona dla multiprocessing
.
Przykład:
import multiprocessing
proc = multiprocessing.Process(target=your_proc_function, args=())
proc.start()
# Terminate the process
proc.terminate() # sends a SIGTERM
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-08 00:19:54
Jeśli próbujesz zakończyć cały program, możesz ustawić wątek jako "daemon". Zobacz też Wątek.daemon
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-18 15:54:53
Jak wspomnieli inni, normą jest ustawienie flagi stop. Dla czegoś lekkiego (bez podklasowania wątku, bez zmiennej globalnej), lambda callback jest opcją. (Zwróć uwagę na nawiasy w if stop()
.)
import threading
import time
def do_work(id, stop):
print("I am thread", id)
while True:
print("I am thread {} doing something".format(id))
if stop():
print(" Exiting loop.")
break
print("Thread {}, signing off".format(id))
def main():
stop_threads = False
workers = []
for id in range(0,3):
tmp = threading.Thread(target=do_work, args=(id, lambda: stop_threads))
workers.append(tmp)
tmp.start()
time.sleep(3)
print('main: done sleeping; time to stop the threads.')
stop_threads = True
for worker in workers:
worker.join()
print('Finis.')
if __name__ == '__main__':
main()
Zastąpienie print()
funkcją pr()
, która zawsze spłukuje (sys.stdout.flush()
) może poprawić precyzję wyjścia powłoki.
(testowane tylko na Windows / Eclipse / Python3.3)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-03 00:07:06
Jest to oparte na thread2 -- killable threads (Python recipe)
Musisz wywołać metodę PyThreadState_SetasyncExc(), która jest dostępna tylko przez ctypes.
To zostało przetestowane tylko na Pythonie 2.7.3, ale prawdopodobnie będzie działać z innymi ostatnimi 2.x releases.
import ctypes
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-28 08:56:28
Nigdy nie należy siłą zabijać wątku bez współpracy z nim.
Zabicie wątku usuwa wszelkie gwarancje, że try/finally blokuje ustawione tak, że można pozostawić zablokowane blokady, otwarte pliki itp.
Jedyny raz, kiedy można argumentować, że wymuszone zabijanie wątków jest dobrym pomysłem, to szybkie zabicie programu, ale nigdy pojedynczych wątków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 14:58:49
W Pythonie, po prostu nie można zabić wątku bezpośrednio.
Jeśli naprawdę nie musisz mieć wątku (!), co można zrobić, zamiast korzystać z threading package , jest użycie multiprocessing package . Tutaj, aby zabić proces, możesz po prostu wywołać metodę:
yourProcess.terminate() # kill the process!
Python zabije twój proces (w Unixie przez sygnał SIGTERM, podczas gdy w Windows przez wywołanie TerminateProcess()
). Zwróć uwagę, aby używać go podczas korzystania z kolejki albo Rura! (może uszkodzić dane w kolejce / potoku)
Zauważ, że multiprocessing.Event
i multiprocessing.Semaphore
działają dokładnie w ten sam sposób, odpowiednio threading.Event
i threading.Semaphore
. W rzeczywistości pierwsze są klonami tych ostatnich.
Jeśli naprawdę potrzebujesz użyć wątku, nie ma sposobu, aby go zabić bezpośrednio. Możesz jednak użyć "daemon thread" . W Pythonie wątek może być oznaczony jako daemon :
yourThread.daemon = True # set the Thread as a "daemon thread"
Główny program zakończy działanie, gdy nie / align = "left" / Innymi słowy, gdy twój główny wątek (który jest oczywiście nie-demonem) zakończy swoje operacje, program zakończy działanie, nawet jeśli nadal działają niektóre wątki demona.
Zauważ, że przed wywołaniem metody start()
konieczne jest ustawienie wątku jako daemon
!
daemon
nawet z multiprocessing
. W tym przypadku, gdy główny proces zakończy działanie, próbuje zakończyć wszystkie swoje demoniczne dziecko procesy.
Na koniec proszę zauważyć, że sys.exit()
i os.kill()
nie są wyborami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-24 02:16:31
Możesz zabić wątek, instalując trace w wątku, który zakończy wątek. Zobacz załączony link do jednej z możliwych realizacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-14 01:40:37
Jeśli jawnie wywołujesz time.sleep()
jako część swojego wątku (powiedzmy, że używasz jakiegoś zewnętrznego serwisu), ulepszeniem metody jest użycie timeoutu w metodzie event
'S wait()
gdziekolwiek sleep()
Na przykład:
import threading
class KillableThread(threading.Thread):
def __init__(self, sleep_interval=1):
super().__init__()
self._kill = threading.Event()
self._interval = sleep_interval
def run(self):
while True:
print("Do Something")
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
Następnie uruchomić go
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
Zaletą używania wait()
zamiast sleep()
ing i regularnego sprawdzania zdarzenia jest to, że można programować w dłuższych odstępach czasu snu, wątek jest zatrzymywany niemal natychmiast (gdy w przeciwnym razie byłby sleep()
ing) i moim zdaniem kod do obsługi exit jest znacznie prostszy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 12:05:19
Jest lepiej, jeśli nie zabijasz wątku. Sposobem może być wprowadzenie bloku" try " do cyklu wątku i rzucenie wyjątku, gdy chcesz zatrzymać wątek (na przykład break/return/... to zatrzymuje twoje na / chwilę/...). Użyłem tego w mojej aplikacji i działa...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 15:12:07
Jest zdecydowanie możliwe zaimplementowanie metody Thread.stop
, Jak pokazano w poniższym przykładowym kodzie:
import sys
import threading
import time
class StopThread(StopIteration):
pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
###############################################################################
def main():
test1 = Thread2(target=printer)
test1.start()
time.sleep(1)
test1.stop()
test1.join()
test2 = Thread2(target=speed_test)
test2.start()
time.sleep(1)
test2.stop()
test2.join()
test3 = Thread3(target=speed_test)
test3.start()
time.sleep(1)
test3.stop()
test3.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
def speed_test(count=0):
try:
while True:
count += 1
except StopThread:
print('Count =', count)
if __name__ == '__main__':
main()
Klasa Thread3
wydaje się uruchamiać kod o około 33% szybciej niż klasa Thread2
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-13 15:37:29
Jestem spóźniony do tej gry, ale zmagałem się z podobnym pytaniem i następujące wydaje się, że oba rozwiązują problem idealnie dla mnie i pozwalają mi zrobić podstawowe sprawdzanie stanu wątku i czyszczenie, gdy daemonized sub-thread zakończy działanie: {]}
import threading
import time
import atexit
def do_work():
i = 0
@atexit.register
def goodbye():
print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
(i, threading.currentThread().ident))
while True:
print i
i += 1
time.sleep(1)
t = threading.Thread(target=do_work)
t.daemon = True
t.start()
def after_timeout():
print "KILL MAIN THREAD: %s" % threading.currentThread().ident
raise SystemExit
threading.Timer(2, after_timeout).start()
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-22 18:37:59
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))
T jest Twoim Thread
obiektem.
Przeczytaj źródło Pythona (Modules/threadmodule.c
i Python/thread_pthread.h
) możesz zobaczyć Thread.ident
jest typem pthread_t
, więc możesz zrobić wszystko pthread
może zrobić w Pythonie używać libpthread
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-24 02:16:42
Następujące obejście może być użyte do zabicia wątku:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
Może być używany nawet do kończenia wątków, których kod jest zapisany w innym module, z głównego wątku. Możemy zadeklarować zmienną globalną w tym module i użyć jej do zakończenia wątków / s zrodzonych w tym module.
Zwykle używam tego do zakończenia wszystkich wątków przy wyjściu programu. Może to nie jest idealny sposób na zakończenie wątków, ale może pomóc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 21:59:07
Chcę jeszcze dodać, że jeśli czytasz oficjalną dokumentację w threading lib Python , zaleca się unikać używania "demonicznych" wątków, gdy nie chcesz, aby wątki kończyły się nagle, z flagą, o której wspomniał Paolo Rovelli .
Z oficjalnej dokumentacji:
Wątki demona są nagle zatrzymywane podczas zamykania. Ich zasobów (takich jak otwarte pliki, transakcje bazodanowe itp.) może nie być prawidłowo zwolniony. Jeśli chcesz, aby twoje wątki się zatrzymały z wdziękiem uczyń je nie daemonicznymi i użyj odpowiedniego mechanizmu sygnalizacyjnego, takiego jak Zdarzenie.
Myślę, że tworzenie wątków daemonicznych zależy od twojej aplikacji, ale ogólnie (i moim zdaniem) lepiej unikać ich zabijania lub robienia z nich daemonicznych. W multiprocessingu możesz użyć is_alive()
, aby sprawdzić status procesu i "zakończyć", aby je zakończyć(również unikasz problemów z GIL). Ale czasami możesz znaleźć więcej problemów podczas wykonywania kodu w systemie Windows.
Oraz zawsze pamiętaj, że jeśli masz "żywe wątki", interpreter Pythona będzie uruchomiony na ich oczekiwanie. (Z powodu tego daemonic może pomóc, jeśli nie ma znaczenia nagle się kończy).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:41
Istnieje Biblioteka zbudowana w tym celu, stopit . Chociaż niektóre z tych samych ostrzeżeń wymienionych w niniejszym dokumencie nadal obowiązują, przynajmniej ta biblioteka prezentuje regularną, powtarzalną technikę osiągnięcia określonego celu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-23 23:53:12
Chociaż jest dość stary, to może być dla niektórych przydatne rozwiązanie:
Mały moduł rozszerzający funkcjonalność modułu wątku -- pozwala jednemu wątkowi zgłaszać wyjątki w kontekście innego nić. Podnosząc
SystemExit
, możesz w końcu zabić wątki Pythona.
import threading
import ctypes
def _async_raise(tid, excobj):
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
raise SystemError("PyThreadState_SetAsyncExc failed")
class Thread(threading.Thread):
def raise_exc(self, excobj):
assert self.isAlive(), "thread must be started"
for tid, tobj in threading._active.items():
if tobj is self:
_async_raise(tid, excobj)
return
# the thread was alive when we entered the loop, but was not found
# in the dict, hence it must have been already terminated. should we raise
# an exception here? silently ignore?
def terminate(self):
# must raise the SystemExit type, instead of a SystemExit() instance
# due to a bug in PyThreadState_SetAsyncExc
self.raise_exc(SystemExit)
Pozwala więc "wątkowi zgłaszać wyjątki w kontekście innego wątku" i w ten sposób zakończony wątek może obsłużyć zakończenie bez regularnego sprawdzania flaga przerwania.
Jednak, zgodnie z jego oryginalnym źródłem , są pewne problemy z tym kodem.
[18]}poprosiłem o udostępnienie tej funkcji we wbudowanym module wątku, ale ponieważ ctypes stał się standardową biblioteką (od 2.5), A to
- wyjątek zostanie wywołany tylko podczas wykonywania bajtowego kodu Pythona. Jeśli Twój wątek wywoła natywną / wbudowaną funkcję blokowania, wyjątek zostanie podniesiony tylko wtedy, gdy wykonanie powróci do Pythona kod.
- istnieje również problem, jeśli wbudowana funkcja wewnętrznie wywołuje PyErr_Clear (), co skutecznie anuluje Twoje wyjątek oczekujący. Możesz spróbować podnieść go ponownie.
- tylko typy WYJĄTKÓW mogą być podniesione bezpiecznie. Wyjątki mogą powodować nieoczekiwane zachowanie, a zatem są ograniczone.
- na przykład: t1.raise_exc (TypeError), a nie t1.raise_exc (TypeError ("blah")).
IMHO to bug, zgłosiłem go jako jeden. Aby uzyskać więcej informacji, http://mail.python.org/pipermail/python-dev/2006-August/068158.html
funkcja nie może być implementowana-agnostyczna, może być przechowywana
nienaświetlone.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 07:15:56
Jako, że chcesz mieć wiele wątków tej samej funkcji, jest to IMHO najprostsza implementacja do zatrzymania jednego przez id:
import time
from threading import Thread
def doit(id=0):
doit.stop=0
print("start id:%d"%id)
while 1:
time.sleep(1)
print(".")
if doit.stop==id:
doit.stop=0
break
print("end thread %d"%id)
t5=Thread(target=doit, args=(5,))
t6=Thread(target=doit, args=(6,))
t5.start() ; t6.start()
time.sleep(2)
doit.stop =5 #kill t5
time.sleep(2)
doit.stop =6 #kill t6
Fajną rzeczą jest tutaj, możesz mieć wiele tych samych i różnych funkcji, i zatrzymać je wszystkie przez functionname.stop
Jeśli chcesz mieć tylko jeden wątek funkcji, nie musisz pamiętać identyfikatora. Po prostu przestań, jeśli doit.stop
> 0.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-04 15:59:03
Jak wspomniano w odpowiedzi @Kozyarchuk , Instalacja Trace działa. Ponieważ ta odpowiedź nie zawierała kodu, oto gotowy do użycia przykład:
import sys, threading, time
class TraceThread(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self._run = self.run
self.run = self.settrace_and_run
threading.Thread.start(self)
def settrace_and_run(self):
sys.settrace(self.globaltrace)
self._run()
def globaltrace(self, frame, event, arg):
return self.localtrace if event == 'call' else None
def localtrace(self, frame, event, arg):
if self.killed and event == 'line':
raise SystemExit()
return self.localtrace
def f():
while True:
print('1')
time.sleep(2)
print('2')
time.sleep(2)
print('3')
time.sleep(2)
t = TraceThread(target=f)
t.start()
time.sleep(2.5)
t.killed = True
Zatrzymuje się po wydrukowaniu 1
i 2
. 3
nie jest drukowana.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-01 12:21:00
Tylko po to, aby rozwinąć pomysł @SCB (który był dokładnie tym, czego potrzebowałem), aby stworzyć podklasę KillableThread z niestandardową funkcją:
from threading import Thread, Event
class KillableThread(Thread):
def __init__(self, sleep_interval=1, target=None, name=None, args=(), kwargs={}):
super().__init__(None, target, name, args, kwargs)
self._kill = Event()
self._interval = sleep_interval
print(self._target)
def run(self):
while True:
# Call custom function with arguments
self._target(*self._args)
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
if __name__ == '__main__':
def print_msg(msg):
print(msg)
t = KillableThread(10, print_msg, args=("hello world"))
t.start()
time.sleep(6)
print("About to kill thread")
t.kill()
Naturalnie, podobnie jak w przypadku @SBC, wątek nie czeka na uruchomienie nowej pętli, aby się zatrzymać. W tym przykładzie zobaczysz komunikat "Killing Thread" wydrukowany zaraz po "About to kill thread" zamiast czekać na kolejne 4 sekundy na zakończenie wątku(ponieważ spaliśmy już 6 sekund).
Drugi argument w KillableThread konstruktor jest twoją niestandardową funkcją (print_msg tutaj). Argument Args to argumenty, które będą użyte podczas wywołania funkcji (("hello world")).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-11 23:42:29
Wygląda na to, że działa z pywin32 na windows 7
my_thread = threading.Thread()
my_thread.start()
my_thread._Thread__stop()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-29 10:59:06
Pieter Hintjens -- jeden z założycieli ØMQ -project -- mówi, używając ØMQ i unikając prymitywów synchronizacji, takich jak zamki, muteksy, zdarzenia itp., jest najbezpieczniejszym i najbezpieczniejszym sposobem pisania programów wielowątkowych:
Http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
Obejmuje to poinformowanie wątku podrzędnego, że powinien on anulować jego pracę. Można to zrobić poprzez wyposażenie wątku w gniazdo ØMQ i wyszukanie na tym gnieździe wiadomości mówiąc, że powinno się odwołać.
Link dostarcza również przykład wielowątkowego kodu Pythona z ØMQ.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-09 11:18:10
Oto jeszcze jeden sposób, aby to zrobić, ale z niezwykle czystym i prostym kodem, który działa w Pythonie 3.7 w 2021 roku:
import ctypes
def kill_thread(thread):
"""
thread: a threading.Thread object
"""
thread_id = thread.ident
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')
Zaadaptowane stąd: https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-01 22:23:08
Jeśli naprawdę potrzebujesz możliwości zabicia podrzędnego zadania, użyj alternatywnej implementacji. multiprocessing
i gevent
oba wspierają bezkrytycznie zabijanie "wątku".
Wątek Pythona nie obsługuje anulowania. Nawet nie próbuj. Twój kod może zablokować, uszkodzić lub wyciekać pamięć lub mieć inne niezamierzone "interesujące" trudne do debugowania efekty, które zdarzają się rzadko i nieoznaczoności.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 06:21:26
Możesz wykonać polecenie w procesie, a następnie go zabić, używając identyfikatora procesu. Musiałem zsynchronizować dwa wątki, z których jeden nie wraca sam.
processIds = []
def executeRecord(command):
print(command)
process = subprocess.Popen(command, stdout=subprocess.PIPE)
processIds.append(process.pid)
print(processIds[0])
#Command that doesn't return by itself
process.stdout.read().decode("utf-8")
return;
def recordThread(command, timeOut):
thread = Thread(target=executeRecord, args=(command,))
thread.start()
thread.join(timeOut)
os.kill(processIds.pop(), signal.SIGINT)
return;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-14 19:01:09
Uruchom wątek podrzędny za pomocą setDaemon (True).
def bootstrap(_filename):
mb = ModelBootstrap(filename=_filename) # Has many Daemon threads. All get stopped automatically when main thread is stopped.
t = threading.Thread(target=bootstrap,args=('models.conf',))
t.setDaemon(False)
while True:
t.start()
time.sleep(10) # I am just allowing the sub-thread to run for 10 sec. You can listen on an event to stop execution.
print('Thread stopped')
break
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 20:13:43
To zła odpowiedź, Zobacz komentarze
Oto Jak to zrobić:
from threading import *
...
for thread in enumerate():
if thread.isAlive():
try:
thread._Thread__stop()
except:
print(str(thread.getName()) + ' could not be terminated'))
Daj mu kilka sekund, a Twój wątek powinien zostać zatrzymany. Sprawdź również metodę thread._Thread__delete()
.
thread.quit()
dla wygody. Na przykład, jeśli masz gniazdo w wątku, polecam utworzenie metody quit()
w klasie socket-handle, zakończenie gniazda, a następnie uruchomienie thread._Thread__stop()
wewnątrz twojego quit()
.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 02:11:07