¿Es posible terminar un subproceso en ejecución sin establecer / verificar ningún indicador / semáforo / etc.?
¿Es posible terminar un subproceso en ejecución sin establecer / verificar ningún indicador / semáforo / etc.?
Respuestas:
En general, es un mal patrón matar un hilo abruptamente, en Python y en cualquier idioma. Piense en los siguientes casos:
La buena manera de manejar esto si puede permitírselo (si está administrando sus propios subprocesos) es tener un indicador exit_request que cada subproceso verifique a intervalos regulares para ver si es hora de que salga.
Por ejemplo:
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()
En este código, debe llamar stop()
al hilo cuando desee que salga y esperar a que el hilo salga correctamente usando join()
. El hilo debe verificar la bandera de detención a intervalos regulares.
Sin embargo, hay casos en los que realmente necesitas matar un hilo. Un ejemplo es cuando está ajustando una biblioteca externa que está ocupada por llamadas largas y desea interrumpirla.
El siguiente código permite (con algunas restricciones) generar una excepción en un hilo de Python:
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 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 excpetion in the context of the
thread represented by this instance.
"""
_async_raise( self._get_my_tid(), exctype )
(Basado en hilos eliminables de Tomer Filiba. La cita sobre el valor de retorno de PyThreadState_SetAsyncExc
parece ser de una versión antigua de Python ).
Como se señaló en la documentación, esto no es una bala mágica porque si el hilo está ocupado fuera del intérprete de Python, no detectará la interrupción.
Un buen patrón de uso de este código es hacer que el hilo detecte una excepción específica y realice la limpieza. De esa manera, puede interrumpir una tarea y aún tener la limpieza adecuada.
SO_REUSEADDR
opción de socket para evitar Address already in use
errores.
None
en lugar de 0
para el res != 1
caso, y tuve que llamar ctypes.c_long(tid)
y pasar a que ningún ctypes función más que el tres veces al día directamente.
No hay una API oficial para hacer eso, no.
Debe utilizar la API de la plataforma para eliminar el hilo, por ejemplo, pthread_kill o TerminateThread. Puede acceder a dicha API, por ejemplo, a través de pythonwin o mediante ctypes.
Tenga en cuenta que esto es inherentemente inseguro. Probablemente conducirá a la basura incobrable (de las variables locales de los marcos de la pila que se convierten en basura), y puede conducir a puntos muertos, si el hilo que se está matando tiene el GIL en el momento en que se mata.
Una multiprocessing.Process
latap.terminate()
En los casos en que quiero matar un hilo, pero no quiero usar banderas / bloqueos / señales / semáforos / eventos / lo que sea, promuevo los hilos a procesos completos. Para el código que usa solo unos pocos hilos, la sobrecarga no es tan mala.
Por ejemplo, esto es útil para terminar fácilmente "hilos" auxiliares que ejecutan el bloqueo de E / S
La conversión es trivial: en el código relacionado, reemplace todos threading.Thread
con multiprocessing.Process
y todos queue.Queue
con multiprocessing.Queue
y agregue las llamadas requeridas p.terminate()
a su proceso padre que quiere matar a su hijop
Consulte la documentación de Python paramultiprocessing
.
multiprocessing
es bueno, pero tenga en cuenta que los argumentos se enredan en el nuevo proceso. Entonces, si uno de los argumentos es algo no seleccionable (como a logging.log
), podría no ser una buena idea usar multiprocessing
.
multiprocessing
Los argumentos se encuadran en el nuevo proceso en Windows, pero Linux utiliza la bifurcación para copiarlos (Python 3.7, sin saber qué otras versiones). Por lo tanto, terminará con un código que funciona en Linux pero genera errores de encurtido en Windows.
multiprocessing
con el registro es un negocio complicado. Necesito usar QueueHandler
(ver este tutorial ). Lo aprendí de la manera difícil.
Si está intentando terminar todo el programa, puede configurar el hilo como un "demonio". ver Thread.daemon
Como otros han mencionado, la norma es establecer una bandera de alto. Para algo ligero (sin subclases de Thread, sin variable global), una devolución de llamada lambda es una opción. (Tenga en cuenta los paréntesis en 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()
Reemplazar print()
con una pr()
función que siempre se vacía (sys.stdout.flush()
) puede mejorar la precisión de la salida del shell.
(Solo probado en Windows / Eclipse / Python3.3)
pr()
función?
Esto se basa en thread2 - hilos eliminables (receta de Python)
Debe llamar a PyThreadState_SetasyncExc (), que solo está disponible a través de ctypes.
Esto solo se ha probado en Python 2.7.3, pero es probable que funcione con otras versiones 2.x recientes.
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")
KeyboardInterrupt
para que tengan la oportunidad de limpiar. Si TODAVÍA cuelgan después de eso, entonces SystemExit
es apropiado, o simplemente eliminan el proceso desde una terminal.
pthread_cleanup_push()/_pop()
, sería mucho trabajo implementar correctamente y ralentizaría notablemente al intérprete.
Nunca debe matar a la fuerza un hilo sin cooperar con él.
Matar un hilo elimina cualquier garantía que intente / finalmente bloquee la configuración para que pueda dejar bloqueados, archivos abiertos, etc.
El único momento en que puede argumentar que matar hilos por la fuerza es una buena idea es matar un programa rápidamente, pero nunca hilos individuales.
En Python, simplemente no puedes matar un Hilo directamente.
Si realmente NO necesita tener un subproceso (!), Lo que puede hacer, en lugar de usar el paquete de subprocesos , es usar el paquete de multiprocesamiento . Aquí, para matar un proceso, simplemente puede llamar al método:
yourProcess.terminate() # kill the process!
Python matará su proceso (en Unix a través de la señal SIGTERM, mientras que en Windows a través de la TerminateProcess()
llamada). ¡Presta atención para usarlo mientras usas una cola o una tubería! (puede corromper los datos en la cola / tubería)
Tenga en cuenta que el multiprocessing.Event
y el multiprocessing.Semaphore
trabajo exactamente de la misma manera que el threading.Event
y elthreading.Semaphore
respectivamente. De hecho, los primeros son clones de los últimos.
Si REALMENTE necesita usar un hilo, no hay forma de matarlo directamente. Sin embargo, lo que puede hacer es usar un "hilo de demonio" . De hecho, en Python, un Thread se puede marcar como daemon :
yourThread.daemon = True # set the Thread as a "daemon thread"
El programa principal se cerrará cuando no queden hilos no daemon vivos. En otras palabras, cuando su hilo principal (que es, por supuesto, un hilo que no es de demonio) termine sus operaciones, el programa se cerrará incluso si todavía hay algunos hilos de demonio funcionando.
Tenga en cuenta que es necesario establecer un subproceso como daemon
antes de start()
llamar al método.
Por supuesto que puede y debe usar daemon
incluso con multiprocessing
. Aquí, cuando el proceso principal sale, intenta finalizar todos sus procesos secundarios demoníacos.
Finalmente, tenga en cuenta que sys.exit()
y os.kill()
no son opciones.
Puede matar un subproceso instalando el rastreo en el subproceso que saldrá del subproceso. Vea el enlace adjunto para una posible implementación.
Si está llamando explícitamente time.sleep()
como parte de su hilo (por ejemplo, encuestando algún servicio externo), una mejora con respecto al método de Phillipe es utilizar el tiempo de espera en el event
'swait()
método de donde quiera que ustedsleep()
Por ejemplo:
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()
Entonces para correrlo
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
La ventaja de usar en wait()
lugar de sleep()
comprobar el evento regularmente es que puede programar en intervalos de sueño más largos, el subproceso se detiene casi de inmediato (cuando de otro modo estaría sleep()
ing) y, en mi opinión, el código para manejar la salida es significativamente más simple .
Definitivamente es posible implementar un Thread.stop
método como se muestra en el siguiente código de ejemplo:
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()
La Thread3
clase parece ejecutar código aproximadamente un 33% más rápido que la Thread2
clase.
self.__stop
conjunto en el hilo. Tenga en cuenta que, como la mayoría de las otras soluciones aquí, en realidad no interrumpirá una llamada de bloqueo, ya que la función de rastreo solo se llama cuando se ingresa un nuevo alcance local. También vale la pena señalar que sys.settrace
realmente está destinado a implementar depuradores, perfiles, etc. y como tal se considera un detalle de implementación de CPython, y no se garantiza que exista en otras implementaciones de Python.
Thread2
clase es que ejecuta código aproximadamente diez veces más lento. Algunas personas aún pueden encontrar esto aceptable.
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))
t es suThread
objeto.
Lea la fuente de Python ( Modules/threadmodule.c
y Python/thread_pthread.h
) puede ver que Thread.ident
es un pthread_t
tipo, por lo que puede hacer cualquier cosa que pthread
pueda hacer con el uso de Python libpthread
.
La siguiente solución alternativa se puede usar para matar un hilo:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
Esto puede usarse incluso para terminar hilos, cuyo código está escrito en otro módulo, desde el hilo principal. Podemos declarar una variable global en ese módulo y usarla para terminar los hilos generados en ese módulo.
Usualmente uso esto para terminar todos los hilos a la salida del programa. Puede que esta no sea la manera perfecta de terminar hilos / s pero podría ayudar.
Llegué tarde a este juego, pero he estado luchando con una pregunta similar y lo siguiente parece resolver el problema perfectamente para mí Y me permite hacer una comprobación y limpieza básica del estado del hilo cuando sale el subproceso demonizado:
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()
Rendimientos:
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
SystemExit
el after_timeout
hilo haría algo al hilo principal (que simplemente está esperando que el primero salga en este ejemplo)?
SystemExit
solo tiene dos propiedades especiales: no produce un rastreo (cuando un subproceso sale lanzando uno), y si el subproceso principal sale lanzando uno, establece el estado de salida (mientras espera otros subprocesos que no sean demonios salir).
Una cosa que quiero agregar es que si lees la documentación oficial al enhebrar lib Python , se recomienda evitar el uso de hilos "demoníacos", cuando no quieras que los hilos terminen abruptamente, con la bandera que mencionó Paolo Rovelli .
De la documentación oficial:
Los hilos del demonio se detienen abruptamente en el apagado. Es posible que sus recursos (como archivos abiertos, transacciones de bases de datos, etc.) no se liberen correctamente. Si desea que sus hilos se detengan con gracia, hágalos no demoníacos y utilice un mecanismo de señalización adecuado, como un evento.
Creo que crear hilos demoníacos depende de su aplicación, pero en general (y en mi opinión) es mejor evitar matarlos o hacerlos demoníacos. En el multiprocesamiento puede usar is_alive()
para verificar el estado del proceso y "finalizar" para finalizarlos (también evita los problemas de GIL). Pero puede encontrar más problemas, a veces, cuando ejecuta su código en Windows.
Y recuerde siempre que si tiene "hilos en vivo", el intérprete de Python se ejecutará para esperarlos. (Debido a esto daemonic puede ayudarte si no importa termina abruptamente).
Hay una biblioteca construida para este propósito, detente . Aunque todavía se aplican algunas de las mismas precauciones enumeradas en este documento, al menos esta biblioteca presenta una técnica regular y repetible para lograr el objetivo establecido.
Si bien es bastante antiguo, esta podría ser una solución útil para algunos:
Un pequeño módulo que amplía la funcionalidad del módulo de subprocesos: permite que un subproceso genere excepciones en el contexto de otro subproceso. Al subir
SystemExit
, finalmente puedes matar hilos de python.
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)
Por lo tanto, permite que un "subproceso genere excepciones en el contexto de otro subproceso" y de esta manera, el subproceso terminado puede manejar la terminación sin verificar regularmente un indicador de cancelación.
Sin embargo, según su fuente original , hay algunos problemas con este código.
- La excepción se generará solo cuando se ejecute el código de bytes de Python. Si su hilo llama a una función de bloqueo nativa / incorporada, la excepción se generará solo cuando la ejecución regrese al código python.
- También hay un problema si la función integrada llama internamente a PyErr_Clear (), lo que efectivamente cancelaría su excepción pendiente. Puedes intentar subirlo de nuevo.
- Solo los tipos de excepción se pueden generar de forma segura. Es probable que las instancias de excepción provoquen un comportamiento inesperado y, por lo tanto, estén restringidas.
- Por ejemplo: t1.raise_exc (TypeError) y no t1.raise_exc (TypeError ("blah")).
- En mi humilde opinión es un error, y lo informé como uno. Para más información, http://mail.python.org/pipermail/python-dev/2006-August/068158.html
- Pedí exponer esta función en el módulo de subprocesos incorporado, pero dado que ctypes se ha convertido en una biblioteca estándar (a partir de 2.5), y
es probable que esta característica no sea independiente de la implementación, puede mantenerse
sin exponer.
Pieter Hintjens - uno de los fundadores de ØMQ , dice que usar ØMQ y evitar las primitivas de sincronización como bloqueos, mutexes, eventos, etc., es la forma más segura y segura de escribir programas de subprocesos múltiples:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
Esto incluye decirle a un hilo secundario que debe cancelar su trabajo. Esto se haría equipando el hilo con un zócalo ØMQ y sondeando en ese zócalo un mensaje que indique que debería cancelarse.
El enlace también proporciona un ejemplo de código python multihilo con ØMQ.
Asumiendo que desea tener múltiples subprocesos de la misma función, esta es, en mi humilde opinión, la implementación más fácil para detener uno por 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
Lo bueno es que puedes tener múltiples funciones iguales y diferentes, y detenerlas todas functionname.stop
Si desea tener solo un hilo de la función, entonces no necesita recordar la identificación. Solo detente, si doit.stop
> 0.
Solo para construir sobre la idea de @ SCB (que era exactamente lo que necesitaba) para crear una subclase de KillableThread con una función personalizada:
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()
Naturalmente, como con @SBC, el hilo no espera para ejecutar un nuevo ciclo para detenerse. En este ejemplo, verá el mensaje "Killing Thread" impreso justo después de "About to kill thread" en lugar de esperar 4 segundos más para que se complete el hilo (ya que hemos dormido durante 6 segundos).
El segundo argumento en el constructor KillableThread es su función personalizada (print_msg aquí). El argumento Args son los argumentos que se utilizarán al llamar a la función (("hola mundo")) aquí.
Como se menciona en la respuesta de @ Kozyarchuk , la instalación de trazas funciona. Como esta respuesta no contenía ningún código, aquí hay un ejemplo de trabajo listo para usar:
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
Se detiene después de haber impreso 1
y 2
. 3
No está impreso.
Puede ejecutar su comando en un proceso y luego matarlo usando la identificación del proceso. Necesitaba sincronizar entre dos hilos uno de los cuales no regresa por sí mismo.
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;
Inicie el subproceso con 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
Esta es una mala respuesta, mira los comentarios
Aquí se explica cómo hacerlo:
from threading import *
...
for thread in enumerate():
if thread.isAlive():
try:
thread._Thread__stop()
except:
print(str(thread.getName()) + ' could not be terminated'))
Déle unos segundos, entonces su hilo debería detenerse. Compruebe también elthread._Thread__delete()
método.
Recomendaría un thread.quit()
método por conveniencia. Por ejemplo, si tiene un socket en su hilo, recomendaría crear un quit()
método en su clase socket-handle, terminar el socket y luego ejecutar un thread._Thread__stop()
interior de su quit()
.
_Thread__stop()
simplemente marca un hilo como detenido , ¡en realidad no lo detiene! Nunca hagas esto. Tiene una lectura .
Si realmente necesita la capacidad de eliminar una subtarea, use una implementación alternativa. multiprocessing
y gevent
ambos apoyan matar indiscriminadamente un "hilo".
El subproceso de Python no admite la cancelación. Ni lo intentes. Es muy probable que su código tenga un punto muerto, corrompa o pierda memoria, o tenga otros efectos "interesantes" difíciles de depurar no intencionados que ocurren raramente y de manera no determinante.