Неблокирующий метод для анализа (потокового) XML в python - PullRequest
7 голосов
/ 22 сентября 2009

У меня есть XML-документ, поступающий через сокет, который мне нужно анализировать и реагировать на лету (т. Е. Анализировать частичное дерево). Мне бы хотелось, чтобы это был неблокирующий метод, чтобы я мог делать другие вещи, ожидая поступления дополнительных данных (без потоков).

Нечто подобное iterparse было бы идеальным, если бы оно заканчивало итерацию, когда буфер чтения был пуст, например:

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)

Полагаю, SAX тоже был бы вариантом, но он довольно прост для моих нужд. Есть идеи?

Обновление:

Использование потоков хорошо, но представляет уровень сложности, который я надеялся обойти. Я думал, что неблокирующие вызовы были бы хорошим способом сделать это, но я обнаружил, что это увеличивает сложность анализа XML.

Ответы [ 3 ]

8 голосов
/ 16 февраля 2010

Погружение в источник iterparse предоставило мне решение. Вот простой пример построения дерева XML на лету и обработки элементов после их тегов закрытия:

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)

В моем случае я получил данные от витой, но она должна работать и с неблокирующим сокетом.

4 голосов
/ 23 сентября 2009

Я думаю, что есть два компонента для этого: неблокирующий сетевой ввод-вывод и потоково-ориентированный синтаксический анализатор XML.

В первом случае вам придется выбрать неблокирующую сетьрамки, или накатить собственное решение для этого.Конечно, Twisted будет работать, но мне лично трудно инвертировать структуры управления, чтобы обернуть мой мозг.Скорее всего, вам придется отслеживать состояние в ваших обратных вызовах, чтобы прокормить анализатор.По этой причине я склонен находить Eventlet немного проще для программирования, и я думаю, что он хорошо подошел бы в этой ситуации.

По сути, это позволяет вам писать свой код какесли вы использовали блокирующий вызов сокета (с помощью обычного цикла, генератора или чего угодно), за исключением того, что вы можете создать его в отдельной сопрограмме («гринлет»), которая автоматически выполнит совместный выход, когда яОперации / O блокируются, что позволяет запускать другие сопрограммы.

Это делает использование любого потоково-ориентированного синтаксического анализатора снова тривиальным, потому что код структурирован как обычный блокирующий вызов.Это также означает, что многие библиотеки, которые напрямую не работают с сокетами или другими операциями ввода-вывода (например, анализатором), не нужно специально модифицировать, чтобы они были неблокирующими: если они блокируют, Eventlet выдает сопрограмму.

По общему признанию Eventlet - это немного магия, но я считаю, что у него намного более легкая кривая обучения, чем у Twisted, и в результате получается более простой код, потому что вам не нужно выворачивать свою логику "наизнанку"чтобы соответствовать рамке.

1 голос
/ 23 сентября 2009

Если вы не будете использовать потоки, вы можете использовать цикл обработки событий и опрашивать неблокирующие сокеты.

asyncore - стандартный модуль библиотеки для таких вещей. Twisted - это асинхронная библиотека для Python, но сложная и, вероятно, немного тяжелая для ваших нужд.

В качестве альтернативы, multiprocessing - это альтернатива не поточным потокам, но я предполагаю, что вы не используете 2.6.

Так или иначе, я думаю, вам придется использовать потоки, дополнительные процессы или создавать не менее сложную асинхронную магию.

...