2010-12-27 9 views
5

Sto cercando di capire come posso rendere il mio codice più asincrono usando twistato.deferito/richiamato e esecuzione asincrona

  • Una funzione restituisce un oggetto differita
  • quindi aggiungo un elenco di richiamate
  • primo callback verrà chiamata dopo la funzione differita fornisce qualche risultato attraverso deferred_obj.callback
  • poi, nella catena di callback , il primo callback farà qualcosa con i dati e chiamare il secondo callback
  • ed ecc

tuttavia i callback concatenati non saranno considerati asincroni perché sono concatenati e il ciclo degli eventi continuerà a sparare a ciascuno di essi contemporaneamente finché non ci sarà più, giusto?

Tuttavia, se ho un oggetto differita, e attribuisco come callback deferred_obj.callback come in d.addCallback(deferred_obj.callback) allora questo sarà considerato asincrono, perché il deferred_obj è in attesa dei dati, e quindi il metodo che si passi il i dati sono in attesa anche sui dati, tuttavia una volta che l'oggetto d.callback 'd' elabora i dati, allora chiama deferred_obj.callback tuttavia, poiché questo oggetto è differito, diversamente dal callback concatenato, eseguirà in modo asincrono ... corretto?

Supponendo che tutto il mio codice sia non bloccante, ciò significa che i callback concatenati NON sono asincroni mentre i differenziali concatenati sono corretti?

+6

Si prega di prendere questo e fare uso di esso nel vostro muro di testo: '' ........... –

+0

qualunque cosa significhi:/ – mayotic

+0

voleva dire la tua domanda è molto difficile da leggere in quanto è un muro di testo, quindi dovresti usare un po 'più di spazio ... – Tommy

risposta

7

Il callback sono (per impostazione predefinita) sincrona. Tuttavia, poiché il Twisted doc sottolinea:

Se avete bisogno di uno Differita per aspettare un altro, tutto quello che dovete fare è restituire un anticipate da un metodo aggiunto al addCallbacks.

Quindi è possibile utilizzarlo per eseguire un'elaborazione asincrona nella catena di richiamata. Facciamolo:

from twisted.internet import reactor, defer 

def callback_func_2(result, previous_data): 
    # here we pass the result of the deferred down the callback chain 
    # (done synchronously) 
    print "calling function 1 on result:%s with previous result:%s" % (result, previous_data) 
    return result 

def callback_func(result): 
    #let's do some asynchronous stuff in this callback 
    # simple trick here is to return a deferred from a callback 
    # instead of the result itself. 
    # 
    # so we can do asynchronous stuff here, 
    # like firing something 1 second later and have 
    # another method processing the result 
    print "calling function 1 on result:%s" % result 
    d = defer.Deferred() 
    reactor.callLater(1, d.callback, "second callback") 
    d.addCallback(callback_func_2, result) 
    return d 

def do(): 
    d = defer.Deferred() 
    reactor.callLater(1, d.callback, "first callback") 
    d.addCallback(callback_func) 
    return d 

do() 
reactor.run() 
+0

sì grazie per l'esempio, sto usando un modello simile come quello u ritratta nel mio programma – mayotic

2

Ordinamento, ma non esiste concorrenza in questo tipo di elaborazione degli eventi. Non verrà richiamato nessun nuovo callback fino a quando il codice non tornerà al ciclo degli eventi. Quindi la catena di callback è sincrona. È solo asincrono nel ciclo degli eventi.

Questo è un avvertimento di questo tipo di programmazione, i gestori più eseguiti rapidamente e tornare al ciclo degli eventi ASAP. Non dovrebbe svolgere alcuna attività che richiede tempo in un gestore.

+0

quindi se l'oggetto posticipato ha una catena di callback, il codice non tornerà al ciclo degli eventi fino a quando non sarà passata l'intera catena; tuttavia, se suddivido questa catena utilizzando oggetti posticipati, consento al codice di tornare al ciclo degli eventi e controllare gli altri eventi; corretta? – mayotic

+0

Sì, esattamente. Questo è lo schema generale. Potrebbe essere necessario introdurre timer nel ciclo degli eventi per elaborare grandi blocchi di dati. – Keith

+0

OI, ok grazie mille: D – mayotic

0

L'utilizzo di un rinvio non rende il codice asincrono.

import time 
from twisted.internet import defer 
from twisted.internet import reactor 

def blocking(duration, deferred): 
    print "start blocking" 
    time.sleep(duration) 
    print "finished blocking" 
    deferred.callback(True) 

def other_task(): 
    print "working..." 
    reactor.callLater(1, other_task) 

def finish(result): 
    print "stopping reactor in 2sec" 
    reactor.callLater(2, reactor.stop) 

def failed(reason): 
    print reason 
    print "stopping reactor in 2sec" 
    reactor.callLater(2, reactor.stop) 

def main(): 
    d = defer.Deferred() 
    d.addCallbacks(finish, failed) 
    reactor.callLater(0, blocking, 5, d) 

if __name__ == "__main__": 
    reactor.callLater(0, other_task) 
    main() 
    reactor.run() 

Se si hanno a lungo-esecuzione di codice sincrono, è possibile deferToThread o suddividerla in brevi iterazioni con un Cooperatore (twisted.internet.task)

0

Se si desidera rendere il codice più asincrona con un approccio pulito quindi controllare questo quadro:

https://github.com/iogf/untwisted

Ha codice ordinata, con una documentazione chiara. L'approccio alla gestione dei modelli asincroni è semplice.

Problemi correlati