msgp简介
msgp是MessagePack的缩写,是一种高效的二进制序列化格式,用它官网的一句简单的介绍就是:"It's like JSON.but fast and small.",JSON大家都知道吧,基本JSON能做的事,msgp都能做,而且比JSON更快,更小。 官网在这,大家想详细了解的直接移步到官网去围观吧。
msgp应用在golang
既然msgp这么好,那支持的语言肯定很多吧,没错,到目前为止,msgp对大部分主流的语言都已经支持得很好了,包括golang,官方推荐的库在git上的地址https://github.com/tinylib/msgp 安装就直接go get就行
go get -u -t github.com/tinylib/msgp
这样msgp就直接安装到了golang环境中的工具库中。
由于msgp的原理是将字符序列化为二进制格式,因此需要一些转换代码来辅助序列化,当然这些代码并不用我们手动编写,而是由msgp工具生成,结合go1.4以后出来的子命令go generate,在编译前生成所需的辅助代码,就可以调用msgp库中的序列化方法了
package main
import (
"fmt"
)
//go:generate msgp
type Foo struct {
Bar string `msg:"bar"`
Baz float64 `msg:"baz"`
}
func main() {
fmt.Println("Nothing to see here yet!")
}
上面这段代码关键是部分就是那段注释//go:generate msgp,实际上并不是普通的注释,而是上面说的命令go generate 命令,在这个包下面运行go generate,就会调用msgp命令,这个包下面所有文件只要写有这行注释都会自动生成对应的辅助代码。
$ go generate
======== MessagePack Code Generator =======
>>> Input: "main.go"
>>> Wrote and formatted "main_gen.go"
>>> Wrote and formatted "main_gen_test.go"
$ ls
main.go main_gen.go main_gen_test.go
上面看到我们执行了go generate 命令,就生成了两个新的文件,从文件名我们可以看出主要的辅助代码实际在main_gen.go这个文件中,main_gen_test.go实际是一个测试文件,里面包含了对生成代码的测试,还有序列化的效率输出。
在生成的辅助代码中,实际上就是给Foo这个struct添加了几个方法,包括DecodeMsg,EncodeMsg,MarshalMsg,UnmarshalMsg这些编码、解码、序列化和反序列化方法,还有一个MsgSize,返回被序列化的数据所需的最大字节数。生成的代码太长,这里就不贴出来了,详细代码可以去msgp库的git仓库查看,或者自己动手生成。
上面说到我们调用go generate命令,实际是调用了msgp这个命令,因此实际上我们可以直接调用这个命令。
$ msgp
No file to parse.
直接不带参数,输出了一条错误信息,无文件解析,那么肯定是少了某些参数,根据经验,我们带上-h参数
$ msgp -h
Usage of msgp:
-file string
input file
-io
create Encode and Decode methods (default true)
-marshal
create Marshal and Unmarshal methods (default true)
-o string
output file
-tests
create tests and benchmarks (default true)
-unexported
also process unexported types
果然,msgp命令运行需要的参数出来了,根据它的解释,解析某个文件需要后面接 -file 加文件名,其它的参数都有默认值,我们先删掉之前生成的文件,直接用msgp命令试一下
$ rm main_gen.go main_gen_test.go
kingsoftdeMac-mini:msgptest kingsoft$ msgp -file main.go
======== MessagePack Code Generator =======
>>> Input: "main.go"
>>> Wrote and formatted "main_gen.go"
>>> Wrote and formatted "main_gen_test.go"
跟预期的结果一样,就是之前go generate命令一样的结果,因此可以知道,在代码中输入//go:generate msgp,则表示在执行go generate命令时,实际调用的是msgp -file + 对应文件名。那么如果我们需要添加其它的参数该怎么做呢?对,就是你想的那样,直接在//go:generate msgp后添加,比如只需要序列化,不需要编码,//go:generate msgp -io=false 在生成代码时,DecodeMsg,EncodeMsg就不会生成;-marshal同理;想自定义生成的文件名,-o=myfilename;不需要生成测试文件,-tests=false 等等,就不一一列举了。
到这里,msgp在golang中如何使用就介绍到这里了。什么?你说我根本没介绍使用啊,这只是生成了辅助代码。。。呵呵,确实,不过方法都给你生成了,直接调用不就完了么哈哈,这里篇幅有限,就不举例了。
使用感想
我需要在项目中使用msgp,是因为之前项目中大量使用的JSON确实已经对项目的性能造成了瓶颈,使用msgp一开始是为了解决JSON太大,占用redis缓存太多,导致可缓存数据不多,命中率不高的问题。更换了msgp后,大小问题确实解决了,但实际上并不是很理想,大概就减少了个15%左右的空间,但另我想不到的是,还有个意外收获,它确实是比之前的JSON解析快得多了,直接把整个项目对系统的负载都降了下来,简直惊喜。
坑
这里的坑并不是指msgp的坑,而是我再安装过程中遇到的坑。前几天电脑磁盘坏了,换了个新的,重新搭建了golang环境,也重新安装了msgp,然而在我更新了一个字段需要重新生成代码的时候,运行msgp,却报了一个错
exec: "msgp": executable file not found in $PATH
很好理解,就是在path中找不到msgp这个命令,在百度google都找不到结果后,仔细查看go环境的配置发现其中一个环境配置错了,导致找不到msgp程序,就是go bin环境,go get安装的工具都安装在go bin目录下,需要配置正确才能正确运行。
另外这种需要生成辅助代码也确实有个不好的地方,那就是每次需要添加个参数,都需要重新运行更新一遍代码,不然编译不过,也有点坑啊o(╯□╰)o
以上。