为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中加速 JSON 解析

在 Go 中加速 JSON 解析

Go
弑天下 2021-11-15 17:19:09
我们有事务日志文件,其中每个事务都是 JSON 格式的一行。我们经常需要选取数据的选定部分,执行一次转换,然后将结果以特定格式输入另一个系统。我写了一个 Python 脚本来满足我们的需求,但我希望 Go 会更快,并让我有机会开始学习 Go。所以,我写了以下内容:package mainimport "encoding/json"import "fmt"import "time"import "bufio"import "os"func main() {    sep := ","    reader := bufio.NewReader(os.Stdin)    for {        data, _ := reader.ReadString('\n')        byt := []byte(data)        var dat map[string]interface{}        if err := json.Unmarshal(byt, &dat); err != nil {            break        }        status := dat["status"].(string)        a_status := dat["a_status"].(string)        method := dat["method"].(string)        path := dat["path"].(string)        element_uid := dat["element_uid"].(string)        time_local := dat["time_local"].(string)        etime, _ := time.Parse("[02/Jan/2006:15:04:05 -0700]", time_local)        fmt.Print(status, sep, a_status, sep, method, sep, path, sep, element_uid, sep, etime.Unix(), "\n")    }}编译时没有抱怨,但我对缺乏性能改进感到惊讶。为了测试,我将 2,000,000 行日志放入 tmpfs(以确保磁盘 I/O 不会成为限制)并比较脚本的两个版本。我的结果:$ time cat /mnt/ramdisk/logfile | ./stdin_conv > /dev/null real    0m51.995s$ time cat /mnt/ramdisk/logfile | ./stdin_conv.py > /dev/null real    0m52.471s$ time cat /mnt/ramdisk/logfile > /dev/null real    0m0.149s怎样才能更快地做到这一点?我已经做了一些初步的努力。例如,ffjson 项目建议创建静态函数,使反射变得不必要;但是,到目前为止,我未能使其正常工作,出现错误:Error: Go Run Failed for: /tmp/ffjson-inception810284909.goSTDOUT:STDERR:/tmp/ffjson-inception810284909.go:9:2: import "json_parse" is a program, not an importable package:此外,我上面的内容不会被认为是静态类型的吗?可能不是——我对 Go 的关注点在耳后。我曾尝试在 Go 代码中有选择地禁用不同的属性,以查看某个属性是否特别有问题。没有一个对性能产生明显影响。关于提高性能的任何建议,或者这仅仅是编译语言没有比其他语言有实质性好处的情况吗?
查看完整描述

3 回答

?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

尝试使用类型删除所有这些不必要的赋值和类型断言;


type RenameMe struct {

     Status string `json:"status"`

     Astatus string `json:"a_status"`

     Method string `json:"method"`

     Path string `json:"path"`

     ElementUid string `json:"element_uid"`

     TimeLocal time.Time `json:"time_local"`

     Etime time.Time // deal with this after the fact

}


data := &RenameMe{}

if err := json.Unmarshal(byt, data); err != nil {

            break

        }


data.Etime,  _ := time.Parse("[02/Jan/2006:15:04:05 -0700]", time_local)

我不会测试它以确保它胜过您的代码,但我敢打赌它会大大提高。试一试,请告诉我。


查看完整回答
反对 回复 2021-11-15
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

http://jsoniter.com/宣称自己是最快的 json 解析器,提供了 golang 和 java 实现。可以使用两种类型的api。并且预先注入的 json 对象定义是可选的。


查看完整回答
反对 回复 2021-11-15
?
九州编程

TA贡献1785条经验 获得超4个赞

检查https://github.com/pquerna/ffjson

我看到了标准库采用的标准 json marshal/unmarshal 方法的 3 倍改进。它通过重写源代码并消除对反射的需要来实现。



查看完整回答
反对 回复 2021-11-15
  • 3 回答
  • 0 关注
  • 173 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信