7

我有一个通过套接字传入的 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 也是一种选择,但 iterparse 对我的需要来说似乎更简单。有任何想法吗?

更新:

使用线程很好,但引入了我希望回避的复杂程度。我认为非阻塞调用将是一个很好的方法,但我发现它增加了解析 XML 的复杂性。

4

3 回答 3

8

深入研究 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)

在我的情况下,我最终从扭曲的数据中提供了数据,但它也应该与非阻塞套接字一起使用。

于 2010-02-16T02:18:32.977 回答
4

我认为这有两个组件,非阻塞网络 I/O 和面向流的 XML 解析器。

对于前者,您必须选择一个非阻塞网络框架,或者为此推出您自己的解决方案。Twisted 肯定会起作用,但我个人发现控制框架的反转很难让我的大脑围绕。您可能必须跟踪回调中的许多状态才能为解析器提供数据。出于这个原因,我倾向于发现Eventlet更容易编程,而且我认为它很适合这种情况。

从本质上讲,它允许您编写代码,就好像您正在使用阻塞套接字调用(使用普通循环或生成器或任何您喜欢的东西),除了您可以将它生成到一个单独的协程(“greenlet”)中,它将自动当 I/O 操作阻塞时执行协作让出,从而允许其他协程运行。

这使得使用任何面向流的解析器再次变得微不足道,因为代码的结构类似于普通的阻塞调用。这也意味着许多不直接处理套接字或其他 I/O 的库(例如解析器)不必特别修改为非阻塞:如果它们阻塞,Eventlet 会产生协程。

诚然,Eventlet有点神奇,但我发现它比 Twisted 学习曲线更容易,并且代码更简单,因为您不必将逻辑“从里到外”翻转以适应框架。

于 2009-09-23T19:24:28.637 回答
1

如果您不使用线程,则可以使用事件循环并轮询非阻塞套接字。

asyncore是此类东西的标准库模块。Twisted是Python异步库,但很复杂,可能有点重量级,可以满足您的需求。

或者,multiprocessing是非线程线程替代方案,但我假设您没有运行 2.6。

无论哪种方式,我认为您将不得不使用线程、额外的进程或编织一些同样复杂的异步魔法。

于 2009-09-23T18:58:00.757 回答