go - 与protobuf相比,flatbuffer序列化性能慢

标签 go protocol-buffers flatbuffers

使用以下IDL文件,我的目的是测量Flatbuffer的序列化速度。我正在使用golang进行分析

namespace MyFlat;

struct Vertices {
    x : double;
    y  :double;

}
table Polygon  {

    polygons : [Vertices];
}

table Layer {

    polygons : [Polygon];
}
root_type Layer;

这是我编写的用于计算的代码

包主
import (
    "MyFlat"
    "fmt"
    "io/ioutil"
    "log"
    "strconv"
    "time"

    flatbuffers "github.com/google/flatbuffers/go"
)

func calculation(size int, vertices int) {
    b := flatbuffers.NewBuilder(0)
    var polyoffset []flatbuffers.UOffsetT

    rawSize := ((16 * vertices) * size) / 1024
    var vec1 flatbuffers.UOffsetT
    var StartedAtMarshal time.Time
    var EndedAtMarshal time.Time
    StartedAtMarshal = time.Now()
    for k := 0; k < size; k++ {

        MyFlat.PolygonStartPolygonsVector(b, vertices)

        for i := 0; i < vertices; i++ {
            MyFlat.CreateVertices(b, 2.0, 2.4)

        }

        vec1 = b.EndVector(vertices)
        MyFlat.PolygonStart(b)
        MyFlat.PolygonAddPolygons(b, vec1)
        polyoffset = append(polyoffset, MyFlat.PolygonEnd(b))

    }

    MyFlat.LayerStartPolygonsVector(b, size)
    for _, offset := range polyoffset {
        b.PrependUOffsetT(offset)
    }
    vec := b.EndVector(size)
    MyFlat.LayerStart(b)
    MyFlat.LayerAddPolygons(b, vec)
    finalOffset := MyFlat.LayerEnd(b)

    b.Finish(finalOffset)
    EndedAtMarshal = time.Now()

    SeElaprseTime := EndedAtMarshal.Sub(StartedAtMarshal).String()
    mybyte := b.FinishedBytes()
    file := "/tmp/myflat_" + strconv.Itoa(size) + ".txt"
    if err := ioutil.WriteFile(file, mybyte, 0644); err != nil {
        log.Fatalln("Failed to write address book:", err)
    }

    StartedAt := time.Now()

    layer := MyFlat.GetRootAsLayer(mybyte, 0)

    size = layer.PolygonsLength()
    obj := &MyFlat.Polygon{}
    layer.Polygons(obj, 1)

    for i := 0; i < obj.PolygonsLength(); i++ {
        objVertices := &MyFlat.Vertices{}
        obj.Polygons(objVertices, i)
        fmt.Println(objVertices.X(), objVertices.Y())
    }

    EndedAt := time.Now()
    DeElapseTime := EndedAt.Sub(StartedAt).String()
    fmt.Println(size, ",", vertices, ", ", SeElaprseTime, ",", DeElapseTime, ",", (len(mybyte) / 1024), ",", rawSize)
}

func main() {

    data := []int{500000, 1000000, 1500000, 3000000, 8000000}

    for _, size := range data {
        //calculation(size, 5)
        //calculation(size, 10)
        calculation(size, 20)

    }
}

问题是我发现与具有类似idl的probbuff相比,序列化非常慢。

对于3M多边形,序列化大约需要4.1167037s。在protobuf中占一半。 Flatbuf的灭菌时间非常短(以微秒为单位)。在原虫中它的含量很高。但是,即使我同时添加这两个flatbuf性能,它的性能也会降低。

您是否看到任何优化的序列化方式。 Flatbuffer具有用于字节向量的createBinaryVector方法,但是没有直接方法可以从现有的用户定义类型向量中序列化多边形向量。

我也添加了protobuf代码

语法='proto3';
package myproto; 
message Polygon {
                 repeated double v_x = 1 ;
                 repeated  double v_y = 2 ;
            }
message CADData {


       repeated Polygon polygon = 1;
        string layer_name = 2;
} 

使用protobuf进行编码
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "math/rand"
    "myproto"
    "strconv"
    "time"

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

func calculation(size int, vertices int) {
    var comp []*myproto.Polygon
    var vx []float64
    var vy []float64
    for i := 0; i < vertices; i++ {
        r := 0 + rand.Float64()*(10-0)
        vx = append(vx, r)
        vy = append(vy, r/2)

    }
    rawSize := ((16 * vertices) * size) / 1024
    StartedAtMarshal := time.Now()

    for i := 0; i < size; i++ {
        comp = append(comp, &myproto.Polygon{

            VX: vx,
            VY: vy,
        })
    }
    pfs := &myproto.CADData{
        LayerName: "Layer",
        Polygon:   comp,
    }
    data, err := proto.Marshal(pfs)
    if err != nil {
        log.Fatal("marshaling error: ", err)
    }
    EndedAtMarshal := time.Now()
    SeElaprseTime := EndedAtMarshal.Sub(StartedAtMarshal).String()
    file := "/tmp/myproto_" + strconv.Itoa(size) + ".txt"
    if err := ioutil.WriteFile(file, data, 0644); err != nil {
        log.Fatalln("Failed to write address book:", err)
    }

    StartedAt := time.Now()

    serialized := &myproto.CADData{}
    proto.Unmarshal(data, serialized)
    EndedAt := time.Now()
    DeElapseTime := EndedAt.Sub(StartedAt).String()
    fmt.Println(size, ",", vertices, ", ", SeElaprseTime, ",", DeElapseTime, ",", (len(data) / 1024), ",", rawSize)
}

func main() {
    data := []int{500000, 1000000, 1500000, 3000000, 8000000}
    for _, size := range data {
        //  calculation(size, 5)
        //calculation(size, 10)
        calculation(size, 20)

    }
}

最佳答案

您提供的时间是进行序列化,反序列化还是同时进行?

您的反序列化代码可能完全由fmt.Println主导。您为什么不做sum += objVertices.X() + objVertices.Y()并在计时完成后打印sum?您可以将objVertices := &MyFlat.Vertices{}拉出循环吗?

您没有发布protobuf代码。您是否在时间上包括创建序列化对象树的时间(在Protobuf中使用,而在FlatBuffers中则不需要)?同样,您是否在进行定时(反序列化)至少1000倍左右,因此可以在比较中包括GC的成本(Protobuf分配了很多对象,FlatBuffers分配了很少/没有)。

如果执行上述操作后,它仍然比较慢,请在FlatBuffers github问题上发帖,Go端口的作者也许可以提供进一步的帮助。确保同时发布系统的完整代码和完整的计时。

通常要注意:FlatBuffers的设计将使其与C / C++中的Protobuf产生最大的性能差距。也就是说,Go中的速度仍然应该更快。 Go的不幸之处在于,它无法最大限度地发挥性能潜力。

关于go - 与protobuf相比,flatbuffer序列化性能慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60506304/

相关文章:

go - 在栏位名称前撷取csv空间

function - 戈朗 : custom template function "capture"

go - 如果在第一次迭代和第二次迭代之间有一个小时刻

java - Android 和 Eclipse 的 Protocol Buffer : NoClassDefFoundError

java - 如何从 prototxt 文件编译protocol buffer java类

vector - 是否可以在 protobuf 消息中包含向量字段以生成 Rust 结构?

go - 有没有更简单的方法来使用 FlatBuffers 序列化 [][]byte?

json - 如何在golang中将字符串转换为json?

c# - 包含 prebuild-event 生成的源文件

c++ - 使用更扁平模式的性能影响