gpt4 book ai didi

c# - 标准 xml 解析器在 Golang 中的性能非常低

转载 作者:IT王子 更新时间:2023-10-29 00:47:53 26 4
gpt4 key购买 nike

我有一个 100Gb 大小的 xml 文件,并在这段代码中使用 SAX 方法解析它

file, err := os.Open(filename)
handle(err)
defer file.Close()
buffer := bufio.NewReaderSize(file, 1024*1024*256) // 33554432
decoder := xml.NewDecoder(buffer)
for {
t, _ := decoder.Token()
if t == nil {
break
}
switch se := t.(type) {
case xml.StartElement:
if se.Name.Local == "House" {
house := House{}
err := decoder.DecodeElement(&house, &se)
handle(err)
}
}
}

但是 golang 工作起来很慢,从执行时间和磁盘使用情况来看似乎是这样。我的硬盘能够以大约 100-120 mb/s 的速度读取数据,但 golang 仅使用 10-13 mb/s。为了实验,我用 C# 重写了这段代码:

using (XmlReader reader = XmlReader.Create(filename)
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "House")
{
//Code
}
break;
}
}
}

并且我加载了完整的硬盘,c# 以 100-110mb/s 的速度读取数据。执行时间缩短约 10 倍。

如何使用 golang 提高 xml 解析性能?

最佳答案

这 5 件事可以帮助提高使用 encoding/xml 库的速度:
(针对具有 75k 个条目的 XMB 进行测试,20MB,%s 应用于前一个项目符号)

  1. 使用明确定义的结构
  2. 在所有结构上实现 xml.Unmarshaller
    • 大量代码
    • 节省 20% 的时间和 15% 的分配
  3. d.DecodeElement(&foo, &token) 替换为 foo.UnmarshallXML(d, &token)
    • 几乎 100% 安全
    • 节省 10% 的时间和分配
  4. 使用 d.RawToken() 而不是 d.Token()
    • 需要手动处理嵌套对象和命名空间
    • 节省 10% 的时间和 20% 的分配
  5. 如果使用 d.Skip(),请使用 d.RawToken() 重新实现它

我在我的特定用例上减少了 40% 的时间和分配,代价是更多的代码、样板和可能更糟糕的极端情况处理,但我的输入相当一致,但这还不够.

benchstat first.bench.txt parseraw.bench.txt 
name old time/op new time/op delta
Unmarshal-16 1.06s ± 6% 0.66s ± 4% -37.55% (p=0.008 n=5+5)

name old alloc/op new alloc/op delta
Unmarshal-16 461MB ± 0% 280MB ± 0% -39.20% (p=0.029 n=4+4)

name old allocs/op new allocs/op delta
Unmarshal-16 8.42M ± 0% 5.03M ± 0% -40.26% (p=0.016 n=4+5)

在我的实验中,lack of memoizing issue是 XML 解析器上的大量时间/分配显着减慢的原因,主要是因为 Go 按值复制。

关于c# - 标准 xml 解析器在 Golang 中的性能非常低,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46135167/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com