업데이트
Protobuf, перша помилка яка показала себе через пару тижнів після змін в коді
В проекті ми використовуємо офіційну бібліотеку Protobuf збільшення швидкодії та зменшення використання пам'яті після використання кодогенерації 추가
А потім я дізнався про "Protocol Buffers for Go with Gadgets" github.com/protocolbuffers/protobuf , бібліотеку-fork яка генерує додатковий код щоб прибрати рефексію підчас серіалізації і вже записує в слайс байтів по індексу бо так швидше.
Коли змінював одну бібліотеку на іншу то важливим вважав що стало працювати швидше і написані
І все б було гаразд але в проекті існувала латка яка через пару тижнів після заміни перезапуст
panic: runtime error: index out of range
Латка виглядала приблизно так:
import (
"github.com/golang/protobuf/proto"
google "gitlab.com/go-yp/go-warning-codegeneration/models/protos/google/advertisement"
)
func example() {
var popup = &google.Popup{
Id: uuid(),
Viewed: true,
Clicked: false,
}
// some deep nested function
go func() {
var content, err = proto.Marshal(popup)
if err != nil {
// log error
return
}
// store to database
store(content)
}()
// some delay with other actions
// @temporary hack
go func() {
popup.Clicked = true
var content, err = proto.Marshal(popup)
if err != nil {
// log error
return
}
// store to database again
store(content)
}()
}
І зі стандартною бібліотекою латка працювала без паніки для мікросервісу який працюй но:ті
import (
"github.com/golang/protobuf/proto"
google "gitlab.com/go-yp/go-warning-codegeneration/models/protos/google/advertisement"
"testing"
)
const (
n = 1000000
)
func TestGoogleProtoMarshal(t *testing.T) {
for i := 0; i < n; i++ {
var popup = &google.Popup{
Id: uint32(i),
Viewed: true,
Clicked: false,
}
// some deep nested function
go func() {
_, _ = proto.Marshal(popup)
}()
// @temporary hack
go func() {
popup.Clicked = true
_, _ = proto.Marshal(popup)
}()
}
}
А от з github.com/gogo/protobuf при аналогічному тесті вже видає паніку.
Якщо розглянути згенерований код:
func (m *Popup) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Popup) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
//...
if m.Clicked {
i--
dAtA[i] = 1
i--
dAtA[i] = 0x18
}
//...
return len(dAtA) - i, nil
}
범위를 벗어났습니다.
Звісно латку ми виправили і стало працювати навіть краще.
JSON, 공급업체
Бібліотека github.com/gogo/protobuf теж для серіалізації працює через додатковий код замість використаннек сеф
Але після внесення в easyjson одної з оптимізацій, час від часу почали отримувати зламанний JSON, осй у прик
package tests
import (
"github.com/stretchr/testify/require"
"gitlab.com/go-yp/go-warning-codegeneration/models/jsons/easy"
"testing"
)
const (
// language=JSON
popupWithUnicodeContent = `{
"title": "Some title with symbol \u201Dt",
"description": "Any description"
}`
// language=JSON
popupContent = `{
"title": "Some title",
"description": "Any description"
}`
)
func TestEasyjsonUnmarshalJSON(t *testing.T) {
content := make([]byte, 0, 1024)
content = append(content[:0], popupWithUnicodeContent...)
var popup easy.Popup
unmarshalErr := popup.UnmarshalJSON(content)
require.NoError(t, unmarshalErr)
var expected = easy.Popup{
Title: "Some title with symbol \u201Dt",
Description: "Any description",
}
require.Equal(t, expected, popup)
content = append(content[:0], popupContent...)
/**
Failed:
expected: easy.Popup{Title:"Some title with symbol ”t", Description:"Any description"}
actual : easy.Popup{Title:"Some title with symbol ”t", Description:" }y description"}
*/
require.Equal(t, expected, popup)
}
В easyjson цю помилку вже виправили.
Висновки:
Звісно хочеться використовувати оптимізовані бібліотеки, але стандартні краще протестоваме та
Приклади доступні в easyjson .
Reference
이 문제에 관하여(업데이트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/yaroslavpodorvanov/-gll텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)