Производительность сериализации в Flatbuffer медленная по сравнению с protobuf - PullRequest
1 голос
/ 03 марта 2020

С помощью следующих файлов 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)

    }
}

Проблема в том, что я нахожу его сериализацией довольно медленный по сравнению с protobuff с аналогичным idl.

Для сериализации 3M полигонов он занимает почти 4.1167037 с. Где в протобуф свою половинку взять. Время десерилизации для плоского буфера очень меньше (в микросе c). В протобуф его довольно высоко. Но тем не менее, если я добавлю, как производительность flatbuf будет ниже.

Видите ли вы какой-либо оптимизированный способ сериализации. Flatbuffer имеет метод createBinaryVector для байтового вектора, но нет прямого способа сериализации вектора многоугольника из существующего вектора определенного пользователем типа.

Я добавляю код protobuf также

syntax = ' 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;
} 

Go Код с 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)

    }
}

Ответы [ 2 ]

0 голосов
/ 19 апреля 2020
    b := flatbuffers.NewBuilder(0)

Я не уверен, что поведение "растёт автоматически" в Go для плоских буферов, но я уверен, что требование к автоматическому росту буфера не является предпочтительным шаблоном . Не могли бы вы попробовать сделать то же самое сравнение времени после инициализации буфера с flatbuffers.NewBuilder(moreBytesThanTheMessageNeeds)?

0 голосов
/ 03 марта 2020

Время, которое вы даете, на сериализацию, десериализацию или на то и другое?

В вашем коде десериализации, скорее всего, доминирует fmt.Println. Почему бы вместо этого не сделать sum += objVertices.X() + objVertices.Y() и напечатать sum по истечении времени? Можете ли вы вытащить objVertices := &MyFlat.Vertices{} за пределы l oop?

Вы не опубликовали свой код protobuf. Включаете ли вы во время создание дерева объектов, которое сериализуется (что необходимо для использования в Protobuf, но не в FlatBuffers)? Точно так же вы выполняете синхронизированную (де) сериализацию, по крайней мере, в 1000 раз или около того, так что вы можете включить в сравнение стоимость G C (Protobuf выделяет МНОГО объектов, FlatBuffers выделяет мало / нет)

Если после того, как вы сделаете выше, это все еще медленнее, пост о проблемах GitHub FlatBuffers, авторы порта Go могут помочь в дальнейшем. Убедитесь, что вы публикуете полный код для обеих систем и полную синхронизацию.

Обратите внимание, в целом: конструкция FlatBuffers такова, что она создаст самый большой разрыв в производительности с Protobuf в C / C ++. Тем не менее, это также должно быть намного быстрее в Go. Однако в Go есть неприятные вещи, которые мешают ему максимально увеличить потенциал производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...