使用python 2构建大型xml文件

时间:2018-03-13 11:51:59

标签: python xml multiprocessing lxml concurrent.futures

我正在努力获得在Python 2 / Django中构建大型XML文件的最佳性能。

最终的XML文件是~500mb。使用的第一种方法是 lxml ,但花了3.5小时。我使用 xml.sax(XMLGenerator)进行了测试,花了大约相同的时间,3.5小时。

我正在尝试以最少的内存消耗找到最快的方法。我搜索了几天找到最好的解决方案但没有成功。

lxml代码:

from lxml import etree

tree_var = etree.Element("tree_var", version='1.2')
DATE = etree.SubElement(DATETIME, "DATE")
DATE.text = datetime.date.today().strftime('%Y-%m-%d')
products = FromModel.objects.all().values_list('product_id')
for product in products:
if product.state == 'new':
    ARTICLE = etree.SubElement(tree_var, "ARTICLE", mode=product.state)

XMLGenerator代码:

from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesNSImpl

with open("tmp/" + filename + ".xml", 'wb') as out:

    g = XMLGenerator(out, encoding='utf-8')
    g.startDocument()

    def start_tag(name, attr={}, body=None, namespace=None):
        attr_vals = {}
        attr_keys = {}
        for key, val in attr.iteritems():
            key_tuple = (namespace, key)
            attr_vals[key_tuple] = val
            attr_keys[key_tuple] = key

        attr2 = AttributesNSImpl(attr_vals, attr_keys)
        g.startElementNS((namespace, name), name, attr2)
        if body:
            g.characters(body)

    def end_tag(name, namespace=None):
        g.endElementNS((namespace, name), name)

    def tag(name, attr={}, body=None, namespace=None):
        start_tag(name, attr, body, namespace)
        end_tag(name, namespace)

g.endDocument()

我非常确定xml.sax正在使用更少的内存,并且它实时增加了文件。另一方面,lxml只使用一个巨大的缓冲区在循环结束时创建文件。

任何寻求帮助的想法?

谢谢!

1 个答案:

答案 0 :(得分:0)

阅读时,您可能仍在加载整个输入文件。您可以尝试下面的行,以获取逐步读取文件的示例。 This stackoverflow问题还提供了比下面的代码段更多的上下文。您还可以在iterparse()中指定目标元素,以便可以一次转储整个目标元素。

for event, elem in etree.iterparse(in_file, events=('start', 'end',)):
    if event == 'start':
        start_tag(elem.tag, {}, elem.text)
    elif event == 'end':
        end_tag(elem.tag)

    # It's safe to call clear() here because no descendants will be accessed
    elem.clear()

    # Also eliminate now-empty references from the root node to elem
    while elem.getprevious() is not None:
        del elem.getparent()[0]