2009-09-22 16 views
7

Ho un documento XML in arrivo su un socket che ho bisogno di analizzare e reagire al volo (cioè analizzare un albero parziale). Quello che mi piacerebbe è un metodo non bloccante per farlo, in modo che io possa fare altre cose aspettando che arrivino altri dati (senza thread).Metodo non bloccante per l'analisi (streaming) XML in python

Qualcosa di simile iterparse sarebbe l'ideale se è finito iterazione, quando il buffer di lettura era vuota, ad esempio:

context = iterparse(imaginary_socket_file_wrapper) 
while 1: 
    for event, elem in context: 
     process_elem(elem) 
    # iteration of context finishes when socket has no more data 
    do_other_stuff() 
    time.sleep(0.1) 

Credo SAX sarebbe anche un'opzione, ma iterparse sembra solo più semplice per le mie esigenze. Qualche idea?

Aggiornamento:

utilizzando thread va bene, ma introduce un livello di complessità che speravo di eludere. Ho pensato che le chiamate non bloccanti sarebbero un buon modo per farlo, ma sto scoprendo che aumenta la complessità dell'analisi dell'XML.

risposta

8

L'immersione nella sorgente iterparse ha fornito la soluzione per me.Ecco un semplice esempio di costruzione di un albero XML sugli elementi fly e di elaborazione dopo che i loro tag di chiusura:

import xml.etree.ElementTree as etree 

parser = etree.XMLTreeBuilder() 

def end_tag_event(tag): 
    node = self.parser._end(tag) 
    print node 

parser._parser.EndElementHandler = end_tag_event 

def data_received(data): 
    parser.feed(data) 

Nel mio caso ho finito per alimentarlo dati da contorto, ma dovrebbe funzionare con una presa non bloccante anche .

+0

Non riesco a revocare questa risposta abbastanza – donopj2

+0

Grazie Peter. Ho finalmente trovato un'altra risposta alla mia domanda grazie alla tua risposta. Vedi la mia risposta più elaborata: https://stackoverflow.com/a/44414167/938111 – olibre

1

Se non si utilizzano thread, è possibile utilizzare un ciclo di eventi e eseguire il polling di socket non bloccanti.

asyncore è il modulo libreria standard per tali materiali. Twisted è la libreria asincrona per Python, ma complessa e probabilmente un po 'pesante per le tue esigenze.

In alternativa, multiprocessing è l'alternativa di thread non thread, ma presumo che non si sta eseguendo 2.6.

In un modo o nell'altro, penso che dovrai usare discussioni, processi aggiuntivi o tessere magie asincrone altrettanto complesse.

+0

asyncore sembra ottimo, ma avrei comunque bisogno di un modo di analizzare l'XML che non superi la complessità di mettere semplicemente iterparse in un'altra discussione (diciamo) –

+0

Giusto. Non ero sicuro del motivo per cui i fili erano fuori. Quel Eventlet sembra buono, ma non significativamente più semplice di un thread in questo caso. Per come la vedo io, se vuoi un comportamento concorrente/asincrono/filettato, devi pagare il prezzo di quella complessità in un modo o nell'altro. Una libreria XML (o quasi qualsiasi altra libreria) non arriverà con quel tipo di funzionalità, perché è stata eseguita meglio a un diverso livello di astrazione. – wbg

4

Penso che ci siano due componenti per questo, l'I/O di rete non bloccante e un parser XML orientato al flusso.

Per il primo caso, è necessario selezionare un framework di rete non bloccante o eseguire il rollover della propria soluzione. Twisted certamente funzionerebbe, ma personalmente trovo l'inversione dei quadri di controllo difficile da avvolgere il mio cervello. Probabilmente dovresti tenere traccia di un sacco di stati nelle tue richiamate per alimentare il parser. Per questo motivo tendo a trovare Eventlet un po 'più facile da programmare, e penso che si adatterebbe bene in questa situazione.

In sostanza consente di scrivere il codice come se si stesse utilizzando una chiamata socket di blocco (utilizzando un ciclo normale o un generatore o quello che vuoi), tranne che si può deporre le uova in una coroutine separato (un " greenlet ") che eseguirà automaticamente una resa cooperativa quando le operazioni di I/O si bloccheranno, permettendo così l'esecuzione di altre coroutine.

Ciò rende di nuovo semplice l'uso di qualsiasi parser orientato al flusso, poiché il codice è strutturato come una normale chiamata di blocco. Significa anche che molte librerie che non gestiscono direttamente socket o altri I/O (come ad esempio il parser) non devono essere appositamente modificate per essere non bloccanti: se si bloccano, Eventlet produce la coroutine.

Certo Eventlet è leggermente magia, ma trovo che ha una curva di apprendimento molto più facile che Contorto, e si traduce in codice più semplice perché non si dispone di trasformare la vostra logica "dentro e fuori" per adattare il quadro.

+0

Twisted è davvero piuttosto difficile da capovolgere, anche se una volta capito 'Deferred's, è incredibilmente potente. Ho dato una breve occhiata a eventlet, ed è basato su thread, che l'OP ha escluso. Non ha detto perché i thread non erano un'opzione, però. Se è una questione di complessità, Eventlet sembra pieno di vittoria. – wbg

+0

In realtà Eventlet non richiede thread, ma è ortogonale e compatibile con essi. Utilizza un'estensione C chiamata "greenlet" che implementa le coroutine di cooperazione, che possono essere pensate come una versione generalizzata dei generatori di Python: un greenlet può fornire controllo e riprendere più avanti nel punto in cui era stato interrotto. Eventlet utilizza questa funzionalità per produrre automaticamente qualsiasi greenlet quando esegue un'operazione di I/O che bloccherà, in seguito la riprenderà al termine dell'I/O. In effetti, utilizza un reattore Twisted-like sotto il cofano, ma per programmare i greenlets invece di esporlo direttamente. – edarc

+0

Twisted sembra focalizzato su HTML e HTTP. Esistono esempi di utilizzo di Twisted con semplici socket XML e TCP ol? –