(适用2022年度)
下载protoc程序:
tips:由于centos版本过低,只能用protoc-3.0版本,protoc-3.17.0版本用不了
安装protobuf第三方库(这里面包含了proto-go-gen)
tips:这里如果安装go之后没有添加goroot路径到bash中的话,那么安装会失败。添加方法:
运行指令打开文件:vi ~/.bashrc
添加下面一行,之后保存,重新登录ssh或者打开终端。
export GOPATH=/home/testgo/go
2022年使用的命令安装protobuf-go,之前的get命令不合适了(注意调整系统时间到正确时间,有可能需要科学上网等):
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
运行命令将proto文件生成go代码:
../protoc3.0/bin/protoc --go_out=golang ./*.proto
proto文件生成go代码时候报错:protoc-gen-go: invalid Go import path "." for
解决办法(其中pb为包名):
option go_package = "./;pb";
指定protobuf包版本(此命令会修改go.mod文件):
go mod edit -require google.golang.org/[email protected]
如果发生package is not in goroot错误,需要启用module开关(并非是设置成关闭状态,那是老版本了)
go代码中引入module的代码如下:
import(
pb "hello/pb" (此处hello不能没有,否则会报错:package pb is not in GOROOT (/home/testgo/go/src/pb))
proto "google.golang.org/protobuf/proto" (为什么此处不需要hello?)
)
原因是没有启用module开关(GO111MODULE),需要如下目录结构:
hello/main.go
hello/pb/*.go
hello/go.mod
其中需要在hello目录中运行go mod init hello
import指令中的引入,需要指定的目录下有go代码文件,否则不能正常引入。
整个测试过程中,使用go版本1.19,性能和java,rust,c++对比如下(其中windows的cpu差点,linux的cpu好点):
解析单个protobuf耗时:
go(linux)需要0-2ms;
java(linux)需要首次需要48ms,二次需要5-9ms;
rust在debug下(windows)需要8ms,在release模式下需要第一次2ms,第二次0ms。
rust在linux下(机器不同),耗时1ms。
c++中(linux)需要1ms。
解析10000个protobuf耗时:
go(linux)需要4762ms(关闭gc情况下);
java(linux)需要2451ms;
rust在debug(windows)模式下需要38294ms,在release模式下需要第一次4031ms,第二次7730ms。
rust在linux下(跟windows不一样)耗时3394ms。
c++(linux)中需要3369ms。
据观察java好像会运用多核性能,也可能是java的垃圾回收器的问题导致,java的cpu使用率会达到140%,go最多100%。
c++代码:
附上rust代码:
use std::fs;
use protobuf::Message;
mod login;
mod goods;
mod common;
mod hero;
use crate::login::RoleInfo;
extern crate chrono;
use chrono::prelude::*;
fn main() {
println!("Hello, world!");
let bytes = fs::read("e:\\roleinfo.bs").unwrap(); // 这个是迭代器,不是数组
let mut ba = [0u8;34483]; // RUST没法使用动态数组,这里只能写死长度。
for i in 0..bytes.len(){
ba[i] = bytes[i];
}
let start = Local::now().timestamp_millis();
let ri = RoleInfo::parse_from_bytes(&ba).unwrap();
print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start);
let start = Local::now().timestamp_millis();
let ri = RoleInfo::parse_from_bytes(&ba).unwrap();
print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start);
let start = Local::now().timestamp_millis();
let mut count = 0;
while count < 10000{
let ri = RoleInfo::parse_from_bytes(&ba).unwrap();
count = count + 1;
}
print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start);
let mut count = 0;
while count < 10000{
let ri = RoleInfo::parse_from_bytes(&ba).unwrap();
count = count + 1;
}
print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start);
/* protobuf_codegen_pure::Codegen::new()
.out_dir("src/protos")
.inputs(&["src/protos/common.proto", "src/protos/goods.proto", "src/protos/hero.proto", "src/protos/login.proto"])
.include("src/protos")
.run()
.expect("Codegen failed."); */
}
rust配置Cargo.toml:
[package]
name = "greeting"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
protobuf-codegen-pure = "2"
protobuf="2.5.1"
chrono = "0.4"
GO代码:
package main
import "fmt"
import "time"
import "io/ioutil"
import(
pb "hello/pb"
proto "google.golang.org/protobuf/proto"
)
func main() {
fmt.Println("Hello, World!")
var bs,err=ioutil.ReadFile("./roleinfo.bs")
if(err == nil){
fmt.Printf("read success!len=%v \n", len(bs));
}
startTime:=time.Now().UnixNano() / 1e6;
roleInfo := &pb.RoleInfo{}
if err := proto.Unmarshal(bs, roleInfo); err != nil {
fmt.Println("Failed to parse address book:", err)
}
fmt.Println(roleInfo.GetName());
endTime:=time.Now().UnixNano() / 1e6;
fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime);
startTime=time.Now().UnixNano() / 1e6;
roleInfo= &pb.RoleInfo{}
if err= proto.Unmarshal(bs, roleInfo); err != nil {
fmt.Println("Failed to parse address book:", err)
}
fmt.Println(roleInfo.GetName());
endTime=time.Now().UnixNano() / 1e6;
fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime);
startTime=time.Now().UnixNano() / 1e6;
for i:=0; i < 10000; i++{
roleInfo= &pb.RoleInfo{}
if err= proto.Unmarshal(bs, roleInfo); err != nil {
fmt.Println("Failed to parse address book:", err)
}
}
fmt.Printf("loop end:%s \n", roleInfo.GetName());
endTime=time.Now().UnixNano() / 1e6;
fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime);
startTime=time.Now().UnixNano() / 1e6;
for i:=0; i < 10000; i++{
roleInfo= &pb.RoleInfo{}
if err= proto.Unmarshal(bs, roleInfo); err != nil {
fmt.Println("Failed to parse address book:", err)
}
}
fmt.Printf("loop end 2:%s \n", roleInfo.GetName());
endTime=time.Now().UnixNano() / 1e6;
fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime);
fmt.Println("end!");
}