高效數(shù)據(jù)傳輸之protobuf

protobuf的誕生

以前在不同系統(tǒng)或者不同項(xiàng)目之間傳輸數(shù)據(jù)主要使用XML格式。下面是xml格式的一些優(yōu)缺點(diǎn)。

時(shí)間開銷:XML格式化(序列化)的開銷倒還好;但是XML解析(反序列化)的開銷就不敢恭維啦。俺之前經(jīng)常碰到一些時(shí)間性能很敏感的場(chǎng)合,由于不堪忍受XML解析的速度,棄之如敝履。

空間開銷:雖然XML格式為了有較好的可讀性,但是引入了一些冗余的文本信息。所以空間開銷也不是太好。

由于Google公司賴以吹噓的就是它的海量數(shù)據(jù)和海量處理能力。對(duì)于幾十萬、上百萬機(jī)器的集群,動(dòng)不動(dòng)就是PB級(jí)的數(shù)據(jù)量,哪怕性能稍微提高0.1%也是相當(dāng)可觀滴。所以Google自然無法容忍XML在性能上的明顯缺點(diǎn)。再加上Google從來就不缺造輪子的牛人,所以protobuf也就應(yīng)運(yùn)而生了。

什么是protobuf?

protobuf的開源項(xiàng)目地址

protobuf是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,全稱是protocol buffers;可以用于結(jié)構(gòu)化數(shù)據(jù)串行化,或者說序列化。它很適合做數(shù)據(jù)存儲(chǔ)或 RPC 數(shù)據(jù)交換格式??捎糜谕ㄓ崊f(xié)議、數(shù)據(jù)存儲(chǔ)等領(lǐng)域的語言無關(guān)、平臺(tái)無關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式。

protobuf數(shù)據(jù)格式的定義

在data.proto文件中用proto3的語法封裝自己的數(shù)據(jù),如下:


代碼格式和c語言風(fēng)格差不多,syntax表示你要用的proto語法版本,默認(rèn)是proto2,message是關(guān)鍵詞,Person則是自定義的數(shù)據(jù)結(jié)構(gòu),里面是定義的一些屬性。

關(guān)于proto2的語法,可參考:Protobuf 語法指南

proto3的語法格式,可參考:protobuf3語法

這樣,我們就定義好了一個(gè).proto文件。接下來運(yùn)行g(shù)o get -u github.com/golang/protobuf/protoc-gen-go命令將protoc工具安裝在$PATH/bin中,安裝好之后,在data.proto目錄下打開終端,輸入protoc --go_out=. *.proto ?會(huì)在同目錄下生成data.pb.go文件,這個(gè)文件中包含了如下的函數(shù):

(1) func(m*Person)Reset()? //重置

(2)func(m*Person) String() string ? ?//將Person轉(zhuǎn)化為字符串

(3)func(*Person)ProtoMessage() ? ?//空函數(shù)

(4)func(*Person)Descriptor()([]byte,[]int) ? ?//返回該文件的描述符和一個(gè)[]int{0}的切片

其中(1)(2)(3)函數(shù)實(shí)現(xiàn)了Message接口,見lib.go


現(xiàn)在在main函數(shù)來將Person對(duì)象進(jìn)行編碼和解碼,見代碼

packagemain

import(

? ? "fmt"

? ? "log"

? ? data ?"protobuf3_test/data" ?//導(dǎo)入data.pb.go所在的文件目錄

? ? "github.com/golang/protobuf/proto"

)

func ?main(){

? ? person := &data.Person{

? ? ? ? ?"初級(jí)賽亞人",

? ? ? ? ?"男",

? ? ? ? ?117,

? ? }

? ? protoData,err := proto.Marshal(person) ? ?//將person編碼成protobuf格式的數(shù)據(jù)

? ? if err != nil {

? ? ? ? log.Fatal("marshalingerror:",err)

? ? }

? ? fmt.Println("protobuf編碼之后的數(shù)據(jù)=",protoData)

? ? newPerson := &data.Person{}

? ? err = proto.Unmarshal(protoData,newPerson) ? ?//將protobuf的解碼存入newPerson中

? ? if err != nil {

? ? ? ? ? ?log.Fatal("unmarshalingerror:",err)

? ? }

? ? fmt.Println("protobuf解碼之后的數(shù)據(jù)=",newPerson)

? ? fmt.Println("newPerson.Name=",newPerson.Name)

? ? fmt.Println("newPerson.Sex=",newPerson.Sex)

? ? fmt.Println("newPerson.Age=",newPerson.Age)

? ? if person.String() != newPerson.String() {

? ? ? ? log.Fatalf("datamismatch%q!=%q",person.String(),newPerson.String())

? ? }

}

控制臺(tái)打印的結(jié)果是:


至此完成了protobuf的編碼與解碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容