salir - terminar un if en python
Terminar un programa python de hilos mĂșltiples (7)
¿Cómo hacer una respuesta de programa python multihilo al evento de tecla Ctrl + C?
Editar: el código es así:
import threading
current = 0
class MyThread(threading.Thread):
def __init__(self, total):
threading.Thread.__init__(self)
self.total = total
def stop(self):
self._Thread__stop()
def run(self):
global current
while current<self.total:
lock = threading.Lock()
lock.acquire()
current+=1
lock.release()
print current
if __name__==''__main__'':
threads = []
thread_count = 10
total = 10000
for i in range(0, thread_count):
t = MyThread(total)
t.setDaemon(True)
threads.append(t)
for i in range(0, thread_count):
threads[i].start()
Traté de eliminar join () en todos los hilos, pero todavía no funciona. ¿Es porque el segmento de bloqueo dentro del procedimiento run () de cada hilo?
Editar: Se supone que el código anterior funciona, pero siempre se interrumpió cuando la variable actual estaba en un rango de 5,000-6,000 y en todos los errores como se muestra a continuación.
Exception in thread Thread-4 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner
File "test.py", line 20, in run
<type ''exceptions.TypeError''>: unsupported operand type(s) for +=: ''NoneType'' and ''int''
Exception in thread Thread-2 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner
File "test.py", line 22, in run
Haga que todos los hilos, excepto el principal, sean daemon ( t.daemon = True
en 2.6 o mejor, t.setDaemon(True)
en 2.6 o menos, para cada objeto de hilo t
antes de iniciarlo). De esta forma, cuando el hilo principal recibe KeyboardInterrupt, si no lo detecta o lo atrapa pero decide terminar de todos modos, todo el proceso terminará. Ver los documentos .
editar : acaba de ver el código del OP (no publicado originalmente) y la afirmación de que "no funciona", parece que tengo que agregar ...:
Por supuesto, si quieres que tu hilo principal se mantenga receptivo (p. Ej., Para controlar C), no lo atasques en llamadas de bloqueo, como join
otro hilo, especialmente las llamadas de bloqueo no totalmente inútiles , como la join
de hilos daemon. . Por ejemplo, simplemente cambie el bucle final en el hilo principal del actual (sin sentido y perjudicial):
for i in range(0, thread_count):
threads[i].join()
a algo más sensible como:
while threading.active_count() > 0:
time.sleep(0.1)
si su main no tiene nada mejor que hacer que el que todos los hilos terminen solos, o que se reciba un C de control (u otra señal).
Por supuesto, hay muchos otros patrones utilizables si prefiere que sus hilos no terminen abruptamente (como pueden hacerlo los hilos daemonicos), a menos que ellos también estén atrapados para siempre en bloqueos incondicionales, bloqueos, y cosas por el estilo ;-) .
Hay dos formas principales, una limpia y otra fácil.
La manera más limpia es capturar KeyboardInterrupt en su hilo principal y establecer un indicador que los hilos de su fondo puedan verificar para que sepan salir; aquí hay una versión simple / ligeramente desordenada usando un global:
exitapp = False
if __name__ == ''__main__'':
try:
main()
except KeyboardInterrupt:
exitapp = True
raise
def threadCode(...):
while not exitapp:
# do work here, watch for exitapp to be True
La manera desordenada pero fácil es atrapar KeyboardInterrupt y llamar a os._exit (), que termina todos los hilos inmediatamente.
Prefiero ir con el código propuesto en esta publicación de blog :
def main(args):
threads = []
for i in range(10):
t = Worker()
threads.append(t)
t.start()
while len(threads) > 0:
try:
# Join all threads using a timeout so it doesn''t block
# Filter out threads which have been joined or are None
threads = [t.join(1000) for t in threads if t is not None and t.isAlive()]
except KeyboardInterrupt:
print "Ctrl-c received! Sending kill to threads..."
for t in threads:
t.kill_received = True
Lo que he cambiado es la t.unión de t.join (1) a t.join (1000) . El número real de segundos no importa, a menos que especifique un número de tiempo de espera, el hilo principal seguirá siendo sensible a Ctrl + C. El excepto en KeyboardInterrupt hace que el manejo de la señal sea más explícito.
Si engendras un hilo como so - myThread = Thread(target = function)
- y luego haces myThread.start(); myThread.join()
myThread.start(); myThread.join()
. Cuando se inicia CTRL-C, el hilo principal no se myThread.join()
porque está esperando que bloquee la llamada myThread.join()
. Para solucionar esto, simplemente ponga un tiempo de espera en la llamada .join (). El tiempo de espera puede ser el tiempo que desee. Si desea que espere indefinidamente, simplemente espere mucho tiempo, como 99999. También es una buena práctica hacer myThread.daemon = True
para que todos los subprocesos myThread.daemon = True
cuando el hilo principal (no demonio) finalice.
Siempre puede configurar sus hilos a hilos "daemon" como:
t.daemon = True
t.start()
Y cada vez que el hilo principal muere, todos los hilos mueren con él.
http://www.regexprn.com/2010/05/killing-multithreaded-python-programs.html
Un trabajador puede ser útil para usted:
#!/usr/bin/env python
import sys, time
from threading import *
from collections import deque
class Worker(object):
def __init__(self, concurrent=1):
self.concurrent = concurrent
self.queue = deque([])
self.threads = []
self.keep_interrupt = False
def _retain_threads(self):
while len(self.threads) < self.concurrent:
t = Thread(target=self._run, args=[self])
t.setDaemon(True)
t.start()
self.threads.append(t)
def _run(self, *args):
while self.queue and not self.keep_interrupt:
func, args, kargs = self.queue.popleft()
func(*args, **kargs)
def add_task(self, func, *args, **kargs):
self.queue.append((func, args, kargs))
def start(self, block=False):
self._retain_threads()
if block:
try:
while self.threads:
self.threads = [t.join(1) or t for t in self.threads if t.isAlive()]
if self.queue:
self._retain_threads()
except KeyboardInterrupt:
self.keep_interrupt = True
print "alive threads: %d; outstanding tasks: %d" % (len(self.threads), len(self.queue))
print "terminating..."
# example
print "starting..."
worker = Worker(concurrent=50)
def do_work():
print "item %d done." % len(items)
time.sleep(3)
def main():
for i in xrange(1000):
worker.add_task(do_work)
worker.start(True)
main()
print "done."
# to keep shell alive
sys.stdin.readlines()
thread1 = threading.Thread(target=your_procedure, args = (arg_1, arg_2))
try:
thread1.setDaemon(True) # very important
thread1.start()
except (KeyboardInterrupt, SystemExit):
cleanup_stop_thread();
sys.exit()
Cuando quieras matar el hilo solo usa:
thread1.join(0)