Обережно кодогенерація
збільшення швидкодії та зменшення використання пам'яті після використання кодогенерації の github.com/protocolbuffers/protobuf は、私が最も重要な問題であると考えています.
≥looflyするまで.
А потім я дізнався про "Protocol Buffers for Go with Gadgets" github.com/gogo/protobuf , бібліотеку-fork яка генерує додатковий код щоб прибрати рефексію підчас серіалізації і вже записує в слайс байтів по індексу бо так швидше.
Коли змінював одну бібліотеку на іншу то важливим вважав що працювати швидше написані раніше тести проуши.
І все було гаразд але в проекті латка яка через пару тижнів після заміни перезапустила мікросервіс через паніку:
Латка виглядала приблизно так:
私はあなたのことを知っています:
А от з github.com/gogo/protobuf при аналогічному тесті вже видає паніку.
Якщо розглянути згенерований код:
. Clicked = false, а серіалізація за умов m.Clicked = true is таким чином пориа 範囲外"
Звісно латку ми виправили і стало працювати навіть краще.
Бібліотека easyjson теж для серіалізації працює через додатковий код замість використання рефлексії.
簡単な JSON の使用は簡単ではありません.
easyjson を使用すると、問題が解決されます.
私はあなたのことをよく知っています.
Pриклади доступні в репозиторії .
Protobuf, перша помилка яка показала себе через пару тижнів після змін в коді
≥looflyするまで.
А потім я дізнався про "Protocol Buffers for Go with Gadgets" github.com/gogo/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
}
. Clicked = false, а серіалізація за умов m.Clicked = true is таким чином пориа 範囲外"
Звісно латку ми виправили і стало працювати навіть краще.
JSON はベンダーによって異なります
Бібліотека 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 を使用すると、問題が解決されます.
回答:
私はあなたのことをよく知っています.
Pриклади доступні в репозиторії .
Reference
この問題について(Обережно кодогенерація), 我々は、より多くの情報をここで見つけました https://dev.to/yaroslavpodorvanov/-gllテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol