zoukankan      html  css  js  c++  java
  • Golang ---json解析

    golang官方为我们提供了标准的json解析库–encoding/json,大部分情况下,使用它已经够用了。不过这个解析包有个很大的问题–性能。它不够快,如果我们开发高性能、高并发的网络服务就无法满足,这时就需要高性能的json解析库,目前性能比较高的有json-iteratoreasyjson

    现在我们需要引进一个高性能的json解析库,这里以json-iterator为例,但是我们全部换掉又不放心,所以可以先小范围的测试下,这时候我们就需要两个解析库并存,那么这时候我们如何选择我们需要的解析库编译和运行呢?

    解决上面问题的办法就是条件编译。Go语言为我们提供了基于tags的编译约束来解决这个问题。

    统一JSON库

    我们先举个例子看看结果。现在我们需要两个库并存,所以我们先得统一这两个库的用法(参考适配器模式),这里我们使用一个自定义的json包来适配encoding/jsonjson-iterator

    json/json.go

    // +build !jsoniter
    
    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
    	fmt.Println("Use [encoding/json] package")
    	return json.MarshalIndent(v,prefix,indent)
    }
    

      

    json/jsoniter.go

    // +build jsoniter
    
    package json
    
    import (
    	"fmt"
    	"github.com/json-iterator/go"
    )
    
    var (
    	json = jsoniter.ConfigCompatibleWithStandardLibrary
    )
    
    func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
    	fmt.Println("Use [jsoniter] package")
    	return json.MarshalIndent(v,prefix,indent)
    }
    

      

    目录结构如下:

    json
    ├── json.go
    └── jsoniter.go
    
    

    例子中以MarshalIndent函数为例,我们发现json包下的两个go文件中都有MarshalIndent函数的定义,并且签名一致,但是它们又是使用不同的json解析库实现,这就是我们统一适配包装后的结果,调用统一了。

    Demo演示

    为了区分调用的是哪个json库的具体实现,打印日志,以便区分。现在我们使用json.MarshalIndent测试一下。

    package main
    
    import (
    	"fmt"
    	"json"
    )
    
    func main() {
    	u := user{"Mike", 30}
    	b, err := json.MarshalIndent(u, "", "  ")
    
    	if err != nil {
    		fmt.Println(err)
    	} else {
    		fmt.Println(string(b))
    	}
    
    }
    
    type user struct {
    	Name string
    	Age  int
    }
    

     使用很简单,把一个user结构体对象转为json字符串,并打印出来。我们运行go run main.go看看结果。

    Use [encoding/json] package
    
    {
    
    "Name": "Mike",
    
    "Age": 30
    
    }
    

     保持我们默认使用encoding/json库的方式不变。现在我们换一种编译运行方式:

    go run -tags=jsoniter main.go
    

      这次运行和上次不同的地方在于我们加了-tags=jsoniter,然后就使用了json-iterator这个json库,这就是选择性的条件编译,达到了我们小部分测试新的json库的目的。

     

    条件编译

    我们发现,条件编译的关键在于-tags=jsoniter,也就是-tags这个标志,这就是Go语言为我们提供的条件编译的方式之一。

    好了,回过头来看我们刚开始时json/json.gojson/jsoniter.go这两个Go文件的顶部,都有一行注释:

    // +build !jsoniter
    
    // +build jsoniter
    
    

    这两行是Go语言条件编译的关键。+build可以理解为条件编译tags的声明关键字,后面跟着tags的条件。

    // +build !jsoniter表示,tags不是jsoniter的时候编译这个Go文件。 // +build jsoniter表示,tags是jsoniter的时候编译这个Go文件。

    也就是说,这两种条件是互斥的,只有当tags=jsoniter的时候,才会使用json-iterator,其他情况使用encoding/json

    小结

    利用条件编译,我们实现了灵活选择json解析库的目的,且tags只是其中的一部分,Go语言还可以根据Go文件后缀进行条件编译。

  • 相关阅读:
    【UOJ 53】线段树区间修改
    【洛谷 1057】传球游戏
    【洛谷 2430】严酷的训练
    【UOJ 51】最接近神的人
    【洛谷 1908】逆序对
    【UOJ 50】树状数组2
    Kafka单机安装
    Linux查看磁盘使用情况命令
    CentOS7查看和关闭防火墙
    Kafka学习(三)——Java工具类、Springboot集成批量消费、SparkStreaming集成
  • 原文地址:https://www.cnblogs.com/saryli/p/11407157.html
Copyright © 2011-2022 走看看