使用lxml.etree.iterparse进行线程化问题

时间:2016-01-19 21:03:56

标签: python python-3.x lxml python-multiprocessing

我有一个线程可以生成多个消费者进程,这些进程在大型xml文件上进行大量处理。

我的设计是使用一个简单的单线程来动态解析入站流,并将新对象推送到缓冲区进程管理器中包含的multiprocessing.queues.queue类中。进程管理器定期检查队列的大小,如果消耗过快让队列填满,则会启动另一个消费者。

我的问题是在流解析完成后加入关闭队列的代码是在xml完成​​解析之前执行的!在我看来,这似乎不是下面的代码应该如何工作。请记住,以下代码完全是单线程的。它既不被任何SMP代码调用也不被使用:

clear_ok = False
context = lxml.etree.iterparse(response, events=('end',))
for event, elem in context:
    # Use QName to avoid specifying or stripping the namespace, which we don't need
    if lxml.etree.QName(elem.tag).localname.upper() in obj_elem_map:
        import_buffer.add(obj_elem_map[lxml.etree.QName(elem.tag).localname.upper()](elem=elem))
        clear_ok = True
    if clear_ok:
        elem.clear() #don't fill up a dom we don't need.
        clear_ok = False
results = import_buffer.finish() if block else import_buffer

调用import_buffer.finish()时会发生以下情况:

def finish(self):
    '''
    Notifies the buffer that we are done filling it.
    This command binds to any processes still running and lets them
    finish and then copies and flushes the managed results list.
    '''
    # close the queue and wait until it is consumed
    self.queue.close()
    self.queue.join_thread()
    # make sure the consumers are done consuming the queue
    for csmr in self.running:
        csmr.join()
    # turn this into a list instead of a managed list
    result = list(self.results_list)
    del self.results_list[:]
    if self.callback:
        return self.callback(result)
    else:
        return result

但是我得到一个异常,就是在我已经完成解析之前已经在队列上调用了close()?

Traceback (most recent call last):
  File "./tests/test_smp_framework.py", line 103, in test_kqb_parser_fromfile
    qkbobs = actions.queryQKB(file=fname)
  File "/Users/skyleach/src/smpparser/smpparser/api_actions.py", line 339, in queryQKB
    result = self.parseResponse(source=sourcefile)File "/Users/skyleach/src/smpparser/smpparser/smpapi.py", line 535, in parseResponse
    import_buffer.add(obj_elem_map[lxml.etree.QName(elem.tag).localname.upper()](elem=elem))
  File "/Users/skyleach/src/smpparser/smpparser/smpapi.py", line 212, in add
    self.queue.put(item)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/multiprocessing/queues.py", line 81, in put
    assert not self._closed
AssertionError

1 个答案:

答案 0 :(得分:0)

这不是lxml的故障或多处理故障,而是上下文分配初始化问题。基本上我编码得太快而且犯了一个愚蠢的错误。

在我的缓冲类定义中,我设置的是队列而不是 init 功能。这意味着该类的所有实例的所有队列都是在导入线程导入模块时定义的一个队列。

这就是我编写代码的速度太快了。