2010-02-11 7 views
9

Tengo que escribir una aplicación sencilla que se ejecuta dos hilos: - Hilo de 1: se ejecuta a intervalos cronometrados, digamos cada 1 minuto - rosca 2: sólo un 'normal' while True bucle que hace 'cosas'Hilos en espiral ... ¿cómo usarlos correctamente?

si no el requisito de circular a intervalo de tiempo no habría mirado trenzado en absoluto, pero el sueño sencillo (60) no es lo suficientemente bueno y construcción como:

l = task.LoopingCall(timed_thread) 
l.start(60.0) 
reactor.run() 

se veía muy fácil de lograr lo que quería allí .

Ahora, ¿cómo 'adecuadamente' agrego otro hilo?

veo dos opciones aquí:

  • uso de la biblioteca roscado y ejecutar uno de dos hilos '' pitón ejecutar mi bucle while, y otro reactor.run correr(). Pero Google parece oponerse a este enfoque y sugiere el uso de roscado trenzado
  • Utilice roscado trenzado. Eso es lo que he intentado, pero de alguna manera esto me parece un poco torpe.

Esto es lo que ocurrió:

def timed_thread(): 
    print 'i will be called every 1 minute' 
    return 

def normal_thread(): 
    print 'this is a normal thread' 
    time.sleep(30) 
    return 

l = task.LoopingCall(timed_thread) 
l.start(60.0) 
reactor.callInThread(normal_thread) 
reactor.run() 

que parece funcionar, pero! No puedo detener la aplicación Si presiono^C no haría nada (sin 'callInThread' simplemente se detiene como lo esperaría).^Z bombardea a shell, y si hago 'kill% 1' parece matar el proceso (el shell lo informa), pero el hilo 'normal' sigue en ejecución. kill PID no se desharía de él, y la única cura es kill -9. Muy extraño.

So. ¿Qué estoy haciendo mal? ¿Es un enfoque correcto implementar dos hilos en twisted? ¿No debería molestarme con retorcer? ¿Qué otras alternativas 'estándares' son para implementar llamadas temporizadas? ('Estándar' quiero decir que puedo instalar easy_ o instalarlos, no quiero comenzar a descargar y usar algunos scripts aleatorios de páginas web aleatorias).

+0

Utiliza hilos en retorcido (y en python en general) con mucho cuidado. ¿Qué está haciendo tu "principal"? Un caso de uso frecuente para twisted es como un cliente/servidor de protocolo, realizando solicitudes o escuchando solicitudes. El reactor manejará esas solicitudes y, suponiendo que no sean bloqueantes, podrá disparar una función particular en un intervalo de tiempo particular. – MattH

+0

El peligro con los subprocesos es que si no tiene cuidado, un subproceso podría modificar los datos mientras está siendo utilizado por otro subproceso que causa un comportamiento impredecible. – MattH

+0

todo lo que se debe hacer es disparar estos dos hilos (de hecho son solo 4 líneas como se puede ver en la muestra), ambas funciones son un poco más elaboradas pero nada inusual en términos de procesamiento, otra solo lo inspecciona , pero eso realmente no importa). estos dos hilos no están compartiendo ningún dato por debajo de – rytis

Respuesta

2

Suponiendo que el principal es relativamente no-bloqueo:

import random 
from twisted.internet import task 

class MyProcess: 
    def __init__(self): 
    self.stats = [] 
    self.lp = None 
    def myloopingCall(self): 
    print "I have %s stats" % len(self.stats) 
    def myMainFunction(self,reactor): 
    self.stats.append(random.random()) 
    reactor.callLater(0,self.myMainFunction,reactor) 
    def start(self,reactor): 
    self.lp = task.LoopingCall(self.myloopingCall) 
    self.lp.start(2) 
    reactor.callLater(0,self.myMainFunction,reactor) 
    def stop(self): 
    if self.lp is not None: 
     self.lp.stop() 
    print "I'm done" 

if __name__ == '__main__': 
    myproc = MyProcess() 
    from twisted.internet import reactor 
    reactor.callWhenRunning(myproc.start,reactor) 
    reactor.addSystemEventTrigger('during','shutdown',myproc.stop) 
    reactor.callLater(10,reactor.stop) 
    reactor.run() 
 
$ python bleh.py 
I have 0 stats 
I have 33375 stats 
I have 66786 stats 
I have 100254 stats 
I have 133625 stats 
I'm done 
+0

Esto no usa hilos. – MattH

+0

quiere decir que esto no usa subprocesos de pitón. Sospecho que todavía está enroscado por la retorcida lib? – rytis

+1

No, esto es solo con rosca. Twisted solo usa hilos si se lo dices. Lea http://twistedmatrix.com/documents/current/core/howto/threading.html – MattH

5

Usted no explicó por qué en realidad se necesita hilos aquí. Si lo hubiera hecho, podría haber sido capaz de explicar por qué no lo necesita. ;)

Dejando eso de lado, puedo confirmar que su comprensión básica de las cosas es correcta. Sin embargo, un posible malentendido que puedo aclarar es la noción de que "hilos de pitón" y "hilos trenzados" son diferentes entre sí. Ellos no están. Python proporciona una biblioteca de subprocesos. Todas las API de subprocesos de Twisted se implementan en términos de la biblioteca de subprocesos de Python. Solo la API es diferente.

En cuanto al apagado, tiene dos opciones.

  • Comience su secuencia de ejecución para siempre utilizando las API de subprocesamiento de Python directamente y convierta el subproceso en un demonio. Su proceso puede salir incluso mientras los hilos daemon aún se estén ejecutando. Un posible problema con esta solución es que algunas versiones de Python tienen problemas con hilos daemon que provocarán un bloqueo en el momento del cierre.
  • Crea tu hilo usando las API de Twisted o las API stdlib threading pero también agrega un enlace de cierre trenzado usando reactor.addSystemEventTrigger('before', 'shutdown', f). En ese gancho, comuníquese con el hilo de trabajo y dígale que se apague. Por ejemplo, puede compartir un threading.Event entre el subproceso Twisted y su subproceso y tiene el enganche set. El hilo de trabajo puede verificar periódicamente si se ha configurado y salir cuando se da cuenta de que lo ha sido. Además de no fallar, esto le da otra ventaja sobre los hilos daemon: le permitirá ejecutar algún código de limpieza o finalización en su hilo de trabajo antes de que el proceso finalice.
+0

+1 Hola JP, gracias por la ayuda. No creo que esté a la altura de la tarea de un defensor retorcido. – MattH

+0

np Matt. :) Creo que tu respuesta fue bastante buena, excepto para tratar los misteriosos casos que "puede tomar más de un minuto" para completar. Si supiéramos cuáles eran esos casos, podríamos sugerir una forma de adaptar su solución para tratar con ellos y eliminar realmente el uso de subprocesos. –

+0

vea la descripción en el comentario de respuesta de Matt. difícil de explicar, hay varios casos que debo tratar. tome esto como un ejemplo (que es bastante cercano a la realidad): t1 lee incluso las entradas de digamos calendarios 1mil y coloca los eventos programados para pasar ese minuto en una tabla DB. Eso es. t2 (t3,4, ...) se arrastra por la tabla y realiza las instrucciones desde ella. no es necesario que el evento deba ser procesado en ese preciso momento, es solo que necesita ingresar a la cola en ese momento preciso. entonces t2 (3,4, ...) tienen todo el tiempo del mundo, pero t1 está restringido. – rytis

Cuestiones relacionadas