чтение большого файла xml: кодировка go / xml в два раза медленнее, чем python lxml - PullRequest
5 голосов
/ 02 июля 2019

Я собирался адаптировать go для своих будущих проектов из соображений производительности, но есть большой сюрприз: время работы go составляет 13.974427 с, а время работы питонов - всего 6.593028783798218s Менее половины!

XMLразмер файла более 300 МБ.Вот код питона:

from lxml import objectify
import time

most = time.time()

root = objectify.parse(open(r"c:\temp\myfile.xml", 'rb')).getroot()

if hasattr(root, 'BaseData'):
    if hasattr(root.BaseData, 'SzTTs'):
        total_records = 0
        for sztt in root.BaseData.SzTTs.sztt:
            total_records += 1
print("total_records", total_records)
print("Time elapsed: ", time.time()-most)

, а вот упрощенный код go:

package main

// An example streaming XML parser.

import (
    "encoding/xml"
    "fmt"
    "io"
    "os"
    "time"
)

var inputFile = "c:\\temp\\myfile.xml"

type SzTTs struct {
    Sztt []sztt
}

type sztt struct {
}

func main() {
    xmlFile, err := os.Open(inputFile)
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer xmlFile.Close()

    d := xml.NewDecoder(xmlFile)
    total1 := 0
    total2 := 0
    start := time.Now()
    for {
        // Read tokens from the XML document in a stream.
        t, err := d.Token()
        // If we are at the end of the file, we are done
        if t == nil || err == io.EOF {
            fmt.Println("The end")
            break
        } else if err != nil {
            log.Fatalf("Error decoding token: %s", err)
        }

        // Inspect the type of the token just read.
        switch se := t.(type) {
        case xml.StartElement:

            if se.Name.Local == "SzTTs" {
                var p SzTTs
                // decode a whole chunk of following XML into the
                // variable p which is a Page (se above)
                if err = d.DecodeElement(&p, &se); err != nil {
                    log.Fatalf("Error decoding item: %s", err)
                }
                for i := range p.Sztt {
                    total1 = i
                }
            }
        default:
        }
    }

    fmt.Printf("Total sztt: %d \n", total1)
    fmt.Printf("Elapsed time %s", time.Since(start))
}

Почему такая большая разница?

1 Ответ

3 голосов
/ 02 июля 2019

Чтобы расширить мой комментарий - это ожидается .

Go's encoding/xml написано на чистом Go, тогда как lxml написано на C, по сути. Он использует Cython, который генерирует код C из Python-подобного DSL.

2x - это не большая разница в производительности, IMHO, но если для вас имеет значение каждое последнее падение производительности, подумайте об использовании другого пакета Go - такого, который обернут оптимизированной реализацией C.

Например, libxml (одна из самых популярных реализаций C) имеет несколько оболочек:

Я ожидаю, что они будут намного быстрее, чем encoding/xml.


Edid (2019-07-22): Этот вопрос вдохновил меня на , чтобы больше рассказать о потоковой передаче производительности XML в Go и новой оболочке для интерфейса libxml SAX .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...