#go #plugins #benchmarking
# #Вперед #Плагины #сравнительный анализ
Вопрос:
Я хотел сравнить плагины go, чтобы увидеть, какова разница в производительности. Итак, я создал файл main.go со следующим кодом:
package main
import (
"math/rand"
"strings"
)
// RandString generates and returns a random 50 character string
func RandString(n int) string {
rand.Seed(int64(n))
chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789")
var b strings.Builder
for i := 0; i < 50; i {
b.WriteRune(chars[rand.Intn(len(chars))])
}
return b.String()
}
Затем я превращаю это в plugin.so досье.
go build -buildmode=plugin -o plugin.so main.go
Затем я написал две контрольные функции, чтобы проверить производительность запуска встроенной функции по сравнению с запуском ее через плагин go.
// BenchmarkRandString tests generating a random string without a go plugin
func BenchmarkRandString(b *testing.B) {
for i := 0; i < b.N; i {
RandString(rand.Int())
}
}
// BenchmarkPluginRandString tests generating a random string with a go plugin
func BenchmarkPluginRandString(b *testing.B) {
plug, err := plugin.Open("./plugin.so")
if err != nil {
panic(err)
}
randString, err := plug.Lookup("RandString")
if err != nil {
panic(err)
}
randFunc, ok := randString.(func(n int) string)
if !ok {
panic("unexpected type from module symbol")
}
b.ResetTimer()
for i := 0; i < b.N; i {
randFunc(rand.Int())
}
}
Как я и ожидал, плагин работает немного медленнее, но не намного
BenchmarkRandString-12 128064 8600 нс / оп
BenchmarkPluginRandString-12 132007 8713 нс / оп
Затем я хотел добавить еще 2 теста, поэтому я добавил еще одну функцию для генерации случайного целого числа и построил плагин так же, как и раньше.
// RandInt uses math/rand to return a random integer
func RandInt() int {
return rand.Int()
}
Затем мои новые контрольные функции добавлены поверх двух предыдущих контрольных функций.
// BenchmarkRandInt tests math/rand for generating random integers without a go plugin
func BenchmarkRandInt(b *testing.B) {
for i := 0; i < b.N; i {
RandInt()
}
}
// BenchmarkPluginRandInt uses a go plugin and tests math/rand for generating random integers
func BenchmarkPluginRandInt(b *testing.B) {
plug, err := plugin.Open("./plugin.so")
if err != nil {
panic(err)
}
randInt, err := plug.Lookup("RandInt")
if err != nil {
panic(err)
}
randFunc, ok := randInt.(func() int)
if !ok {
panic("unexpected type from module symbol")
}
b.ResetTimer()
for i := 0; i < b.N; i {
randFunc()
}
}
Теперь, когда я снова запускаю тест, я получаю следующий результат:
BenchmarkRandInt-12 77320668 13,2 нс / оп
BenchmarkPluginRandInt-12 76371756 13,9 нс / оп
BenchmarkRandString-12 136243 8600 нс / оп
BenchmarkPluginRandString-12 142112 8564 нс / оп
Я могу запускать тест снова и снова, и BenchmarkRandString-12 всегда немного медленнее, чем BenchmarkPluginRandString-12, чего я не ожидал. Почему функция плагина go немного быстрее при таком сопоставлении?
У меня есть проект Github со всем исходным кодом, который я использую здесь: https://github.com/uberswe/goplugins/tree/4825172e011da9578553d113bac7933ca9ecd038
Ответ №1:
Что может быть медленнее с функцией «плагина», так это ее загрузка и утверждение типа. Как только вы это сделаете, не должно быть никакого снижения производительности по сравнению с функцией, определенной в вашем приложении.
Такие небольшие отклонения могут быть результатом управления внутренней памятью Go и сборки мусора. Например, если в вашем main_test.go
файле я перемещаюсь BenchmarkPluginRandString()
выше BenchmarkRandString()
, то результат теста «обратный»: BenchmarkRandString()
становится немного медленнее.
Чтобы избавиться от таких недетерминированных факторов, вы можете попробовать запускать тесты изолированно, например, запускать только по одному за раз с
go test -bench BenchmarkRandString
и
go test -bench BenchmarkPluginRandString
И сделайте это несколько раз, и вычислите среднее значение. Таким образом, заметной разницы нет.