2016-01-31 25 views
15

Recentemente, mi sono tuffato nei documenti Twisted. Da quello che ho raccolto, la base della funzionalità di Twisted è il risultato del suo ciclo di eventi chiamato "Reactor". Il reattore ascolta determinati eventi e li invia alle funzioni di callback registrate che sono state progettate per gestire questi eventi. Nel libro, c'è qualche pseudo codice che descrive cosa fa il Reactor ma ho difficoltà a capirlo, non ha alcun senso per me.Come funziona il Twisted Reactor di Python?

while True: 
    timeout = time_until_next_timed_event() 
    events = wait_for_events(timeout) 
    events += timed_events_until(now()) 
    for event in events: 
     event.process() 

Cosa significa?

risposta

25

Nel caso non è ovvio, Si chiama reattore perché esso reagisce attrattive. Il ciclo è come reagisce.

una riga alla volta:

while True: 

Non è realtàwhile True; è più simile a while not loop.stopped. È possibile chiamare reactor.stop() per interrompere il ciclo e (dopo aver eseguito una logica di spegnimento) il ciclo verrà effettivamente chiuso. Ma è raffigurato nell'esempio come while True perché quando si scrive un programma di lunga durata (come spesso sono con Twisted) è meglio presumere che il programma sarà o crash o di correre per sempre, e che "in modo pulito in uscita" non è davvero un'opzione.

 timeout = time_until_next_timed_event() 

Se dovessimo estendere questo calcolo un po ', si potrebbe avere più senso:

def time_until_next_timed_event(): 
    now = time.time() 
    timed_events.sort(key=lambda event: event.desired_time) 
    soonest_event = timed_events[0] 
    return soonest_event.desired_time - now 

timed_events è l'elenco degli eventi in programma con reactor.callLater; cioè le funzioni che l'applicazione ha richiesto a Twisted di funzionare in un determinato momento.

Questa riga qui è la parte "magica" di Twisted. Non riesco ad espandere wait_for_events in modo generale, perché la sua implementazione dipende esattamente da come il sistema operativo rende disponibili gli eventi desiderati. E, dato che i sistemi operativi sono animali complessi e ingannevoli, non posso espanderlo in un modo specifico pur mantenendo abbastanza semplice la risposta alla tua domanda.

Ciò che questa funzione intende dire è, chiedere al sistema operativo, o un wrapper Python attorno ad esso, di bloccare, finché uno o più degli oggetti precedentemente registrati con esso - come minimo, roba come le porte di ascolto e stabilito le connessioni, ma anche possibilmente cose come i pulsanti su cui è possibile fare clic, è "pronto per il lavoro". Il lavoro potrebbe essere la lettura di alcuni byte da un socket quando arrivano dalla rete. Il lavoro potrebbe scrivere byte sulla rete quando un buffer si svuota sufficientemente per farlo. Potrebbe accettare una nuova connessione o eliminarne una chiusa. Ognuno di questi possibili eventi sono funzioni che il reattore può chiamare sugli oggetti: dataReceived, buildProtocol, resumeProducing, ecc., Che verrà illustrato se si passa attraverso il tutorial completo di Twisted.

Una volta che abbiamo la nostra lista di ipotetici oggetti "evento", ognuno dei quali ha un immaginario "process" metodo (i nomi esatti dei metodi sono diversi nel reattore solo a causa di incidenti della storia), quindi tornare a trattare con il tempo:

 events += timed_events_until(now()) 

in primo luogo, questo è supponendo events è semplicemente un list di un abstract Event classe, che ha un metodo process che ogni tipo specifico di evento deve compilare.

A questo punto, il ciclo si è "riattivato", perché wait_for_events, ha interrotto il blocco. Tuttavia, non sappiamo quanti eventi temporali potremmo aver bisogno di eseguire in base a per quanto tempo è "addormentato" per. Potremmo aver dormito per il timeout completo se non si stava verificando, ma se molte connessioni fossero attive, avremmo potuto dormire per davvero in pochissimo tempo. Quindi controlliamo l'ora corrente ("now()"), e aggiungiamo alla lista di eventi che dobbiamo elaborare, ogni evento a tempo con un desired_time che si trova o prima del tempo presente.

Infine,

 for event in events: 
     event.process() 

Questo significa solo che ritorto passa attraverso l'elenco delle cose che ha a che fare e lo fa. In realtà, naturalmente, gestisce le eccezioni attorno a ciascun evento e l'implementazione concreta del reattore spesso chiama direttamente in un gestore di eventi piuttosto che creare un oggetto simile a Event per registrare il lavoro che deve essere eseguito per primo, ma concettualmente questo è solo che succede. event.process qui potrebbe significare chiamare socket.recv() e quindi yourProtocol.dataReceived con il risultato, ad esempio.

Spero che questa spiegazione estesa ti aiuti a capirlo. Se desideri saperne di più su Twisted lavorando su di esso, ti incoraggio a join the mailing list, sali sul canale IRC, #twisted per parlare delle applicazioni o #twisted-dev per lavorare su Twisted stesso, sia su Freenode.

2

cercherò di elaborare:

  • il programma di controllo dei rendimenti e andare a dormire in attesa per gli eventi. Suppongo che la parte più interessante qui sia l'evento. eventi è: su richiesta esterna (packet rete ricevente, clicca su una tastiera, timer, chiamata programma) programma riceve il controllo (in qualche altro filo o nella routine speciale). In qualche modo il sonno in wait_for_events diventa interrotta e wait_for_events restituisce.

  • Su tale occorrenza del controllo del gestore di eventi memorizza le informazioni di tale evento in qualche struttura dati, eventi, che in seguito viene utilizzato per fare qualcosa che gli eventi (event-> processo). Ci può avvenire non solo uno, ma molti eventi nel tempo tra entrata ed uscita di wait_for_events, tutti devono essere trattati. Il event-> processo() procedura è personalizzato e di solito dovrebbe chiamare la parte interessante - Codice contorta dell'utente.