2010-02-11 7 views
9

Ho bisogno di scrivere una semplice applicazione che gestisce due thread: - filettatura 1: viene eseguito in periodi cronometrati, diciamo ogni 1 minuto - filo 2: solo un 'normale', mentre Vero ciclo che fa 'roba'Thread in twisted ... come usarli correttamente?

se non l'obbligo di funzionare a intervallo di tempo non avrei guardato contorto a tutti, ma semplice sonno (60) non è abbastanza buono e la costruzione come:

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

sembrava davvero semplice per ottenere quello che volevo lì .

Ora, come si aggiunge "correttamente" un altro thread?

vedo due opzioni qui:

  • Usa libreria di threading ed eseguire una due 'pitone discussioni' esecuzione di mio ciclo while, e un altro reactor.run esecuzione(). Ma Google sembra opporsi a questo approccio e suggerisce di utilizzare il threading attorcigliato
  • Utilizzare threading attorcigliato. Questo è quello che ho provato, ma in qualche modo questo mi sembra un po 'maldestro.

Ecco cosa mi è venuta:

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() 

che sembra funzionare, ma! Non riesco a fermare l'app. Se premo^C non farebbe nulla (senza 'callInThread' si arresta esattamente come ci si aspetterebbe che sia).^Z bombe verso la shell, e se poi faccio 'kill% 1' sembra che uccida il processo (la shell riporta che), ma il thread 'normale' continua a girare. uccidere PID non se ne libererebbe, e l'unica cura è uccidere -9. Veramente strano.

Così. Che cosa sto facendo di sbagliato? È un approccio corretto implementare due thread in twisted? Non dovrei preoccuparmi di contorcersi? Quali altre alternative "standard" devono implementare le chiamate programmate? ('Standard' Voglio dire che posso installarlo facilmente o installarlo, non voglio iniziare a scaricare e usare script casuali da pagine web casuali).

+0

Si utilizzano i thread in twistato (e in python in generale) con molta attenzione. Cosa sta facendo il tuo "main"? Un caso d'uso frequente per twisted è come un protocollo client/server, facendo richieste o ascoltando richieste. Il reattore gestirà tali richieste e, supponendo che non siano bloccanti, sarà in grado di attivare una determinata funzione in un determinato intervallo di tempo. – MattH

+0

Il pericolo con i thread è che se non si fa attenzione, un thread potrebbe modificare i dati mentre viene utilizzato da un altro thread che causa un comportamento imprevedibile. – MattH

+0

tutto ciò che "main" è pensato per fare è solo sparare a questi due thread (in realtà sono solo 4 linee come si può vedere nell'esempio), entrambe le funzioni sono un po 'più elaborate ma nulla di insolito in termini di elaborazione dell'altro lo ispeziona semplicemente , ma questo non ha molta importanza). questi due thread non condividono alcun dato btw – rytis

risposta

2

Supponendo che il vostro principale è relativamente non-blocking:

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

Questo non utilizza thread. – MattH

+0

vuoi dire che questo non usa i thread python. ho il sospetto che sia ancora infilato dalla libellula contorta? – rytis

+1

No, questo è selezionato come thread. Twisted usa solo i thread se lo dici tu. Leggi una lettura di http://twistedmatrix.com/documents/current/core/howto/threading.html – MattH

5

Lei non ha spiegato il motivo per cui hai veramente bisogno discussioni qui. Se lo avessi fatto, sarei stato in grado di spiegare perché non hai bisogno di usare lo . ;)

A parte questo, posso confermare che la vostra comprensione di base delle cose è corretta. Un possibile fraintendimento che posso chiarire, tuttavia, è la nozione che "i fili di Python" e "I fili intrecciati" siano affatto diversi l'uno dall'altro. Loro non sono. Python fornisce una libreria di threading. Tutte le API di thread di Twisted sono implementate in termini di libreria di threading di Python. Solo l'API è diversa.

Per quanto riguarda l'arresto, sono disponibili due opzioni.

  • Avvia il tuo thread run-forever usando direttamente le API di threading di Python e rendi il thread un demone. Il tuo processo può uscire anche mentre i thread daemon sono ancora in esecuzione. Un possibile problema con questa soluzione è che alcune versioni di Python presentano problemi con i thread di daemon che causano un arresto anomalo al momento dell'arresto.
  • Creare il thread utilizzando le API di Twisted o le API di threading stdlib, ma aggiungere anche un hook di arresto Twisted utilizzando reactor.addSystemEventTrigger('before', 'shutdown', f). In quel gancio, comunica con il thread di lavoro e digli di chiudere. Ad esempio, è possibile condividere uno threading.Event tra il thread Twisted e il thread di lavoro e avere il gancio set esso. Il thread di lavoro può controllare periodicamente per vedere se è stato impostato e uscire quando si accorge che è stato. Oltre a non bloccarsi, questo offre un altro vantaggio rispetto ai thread daemon: ti permetterà di eseguire un codice di pulitura o di finalizzazione nel tuo thread di lavoro prima che il processo venga chiuso.
+0

+1 Ciao JP, grazie per l'assistenza. Non penso di essere all'altezza di un contorto sostenitore. – MattH

+0

np Matt. :) Penso che la tua risposta sia stata abbastanza buona, tranne che per affrontare i misteriosi casi che "potrebbero richiedere più di un minuto" per completare. Se sapessimo che cosa erano quei casi, potremmo essere in grado di suggerire un modo per adattare la soluzione per affrontarli e in realtà eliminare l'uso dei thread. –

+0

vedere la descrizione nel commento di risposta di Matt. difficile da spiegare, ci sono vari casi che ho bisogno di trattare. prendi questo come esempio (che è abbastanza vicino alla realtà): t1 legge anche le voci da diciamo calendari da 1mil e inserisce gli eventi programmati in quel minuto in una tabella DB. questo è tutto. t2 (t3,4, ...) striscia nella tabella ed esegue le istruzioni da esso. non c'è nessuna richiesta che l'evento debba essere elaborato in quel preciso minuto, è solo che ha bisogno di entrare in coda in quel preciso momento nel tempo. così t2 (3,4, ...) ha tutto il tempo del mondo, ma t1 è vincolato. – rytis

Problemi correlati