2009-09-22 18 views
7

Tengo un documento XML que entra por un socket que necesito analizar y reaccionar sobre la marcha (es decir, analizar un árbol parcial). Lo que me gustaría es un método de no bloqueo para hacerlo, de modo que pueda hacer otras cosas mientras espero que entren más datos (sin enhebrar).Método sin bloqueo para analizar XML en python

Algo así como iterparse sería ideal si se terminó la iteración cuando el búfer de lectura estaba vacío, por ejemplo:

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) 

supongo SAX también sería una opción, pero iterparse sólo parece más sencillo para mis necesidades. ¿Algunas ideas?

Actualización:

Uso de hilos está muy bien, pero introduce un nivel de complejidad que tenía la esperanza de eludir. Pensé que las llamadas no bloqueantes serían una buena forma de hacerlo, pero me parece que aumenta la complejidad de analizar el XML.

Respuesta

8

Bucear en la fuente iterparse proporcionó la solución para mí.He aquí un ejemplo sencillo de construir un árbol XML en los elementos de la mosca y el procesamiento después de que sus etiquetas de cierre:

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) 

En mi caso terminé alimentándolo datos de torcido, pero debería funcionar con un zócalo de no bloqueo también .

+0

No puedo votar esta respuesta lo suficiente – donopj2

+0

Gracias Peter. Finalmente encontré otra respuesta a mi pregunta gracias a su respuesta. Ver mi respuesta más elaborada: https://stackoverflow.com/a/44414167/938111 – olibre

1

Si no usará subprocesos, puede usar un bucle de evento y sondear sockets no bloqueantes.

asyncore es el módulo de biblioteca estándar para tales cosas. Twisted es la biblioteca asincrónica para Python, pero compleja y probablemente un poco pesada para sus necesidades.

Alternativamente, multiprocessing es la alternativa de subproceso sin hilo, pero supongo que no está ejecutando 2.6.

De una forma u otra, creo que vas a tener que usar subprocesos, procesos adicionales o tejer alguna magia asíncrona igualmente compleja.

+0

asyncore se ve muy bien, pero aún necesitaría una forma de analizar XML que no exceda la complejidad de simplemente poner iterparse en otro hilo (por ejemplo) –

+0

Derecha. No estaba seguro de por qué los hilos estaban fuera. Ese Eventlets se ve bien, pero no significativamente más simple que un hilo en este caso. De la forma en que lo veo, si quieres un comportamiento concurrente/asincrónico/enhebrado, tendrás que pagar el precio por esa complejidad de una forma u otra. Una biblioteca XML (o casi cualquier otra biblioteca) no va a venir con ese tipo de funcionalidad incorporada, porque se ha hecho mejor en un nivel de abstracción diferente. – wbg

4

Creo que hay dos componentes para esto, la E/S de red sin bloqueo y un analizador XML orientado a flujo.

Para el primero, debe elegir un marco de red no bloqueante o implementar su propia solución para esto. Twisted ciertamente funcionaría, pero personalmente encuentro que la inversión de los marcos de control es difícil de envolver mi cerebro. Es probable que tenga que hacer un seguimiento de un montón de estado en sus devoluciones de llamada para alimentar al analizador. Por esta razón, tiendo a encontrar Eventlet un poco más fácil de programar, y creo que encajaría bien en esta situación.

Esencialmente se le permite escribir el código como si que estaba usando una llamada socket de bloqueo (usando un bucle ordinario o un generador o lo que quiera), excepto que se puede generar en una co-rutina separada (un " greenlet ") que automáticamente realizará un rendimiento cooperativo cuando las operaciones de E/S se bloquearían, permitiendo así que se ejecuten otras corutinas.

Esto hace que el uso de cualquier analizador orientado a flujo sea trivial otra vez, porque el código está estructurado como una llamada de bloqueo normal. También significa que muchas bibliotecas que no tratan directamente con sockets u otras I/O (como el analizador sintáctico, por ejemplo) no tienen que modificarse especialmente para que no sean bloqueantes: si bloquean, Eventlet produce la corutina.

cierto Eventlet es ligeramente magia, pero me parece que tiene una curva de aprendizaje mucho más fácil que Twisted, y resulta en un código más sencillo, ya que no tiene que dar vuelta a su lógica de "adentro hacia afuera" para ajustarse al marco.

+0

Twisted es realmente bastante difícil de entender, aunque una vez que comprendes 'Deferred's, es increíblemente poderoso. He echado un vistazo breve a eventlet, y está basado en hilos, que OP descartó. No dijo por qué los hilos no eran una opción, sin embargo. Si se trata de una cuestión de complejidad, Eventlet parece estar lleno de triunfos. – wbg

+0

En realidad, Eventlet no requiere subprocesos, pero es ortogonal y compatible con ellos. Utiliza una extensión C llamada "greenlet" que implementa corutinas cooperativas, que se puede considerar como una versión generalizada de los generadores de Python: un greenlet puede ceder el control y reanudarse más tarde justo donde lo dejó. Eventlet usa esta capacidad para generar automáticamente cualquier greenlet cuando realiza una operación de E/S que se bloquearía, y luego la reanuda cuando termina la E/S. De hecho, utiliza un reactor tipo Twisted debajo del capó, pero para programar greenlets en lugar de exponerlo directamente. – edarc

+0

Twisted parece estar enfocado hacia HTML y HTTP. ¿Hay algún ejemplo de uso de Twisted con plain ol 'XML y sockets TCP? –

Cuestiones relacionadas