Мы недавно писали про
purego, который позволяет вызывать C-функции из Go без Cgo. speedboost решает ту же задачу, но заходит с другой стороны. Авторы заявляют меньший оверхед на вызов по сравнению с
purego и более низкоуровневый контроль над тем, как именно происходит взаимодействие с shared-библиотекой.Как это работает
API состоит из четырёх шагов. Вы загружаете shared-библиотеку, получаете указатель на символ, описываете сигнатуру функции через дескрипторы типов и вызываете её.
Важная особенность — библиотеку можно встроить прямо в Go-бинарник через
//go:embed. Это значит, что .so / .dylib / .dll файл не нужно таскать отдельно, он будет внутри вашего приложения.Вот пример. Допустим, у нас есть функция
multiply, написанная на Zig и скомпилированная в shared-библиотеку.const std = @import("std");
export fn multiply(a: f64, b: f64) callconv(.c) f64 {
return a * b;
}Go-код, который её вызывает:
//go:embed lib/zig-out/mymath.shared
var sharedLibrary []byte
func main() {
lib, err := sb.LoadLibrary(sharedLibrary)
if err != nil {
panic(err)
}
defer lib.Unload()
mulPtr := lib.GetSymbol("multiply")
cif := sb.SetFuncSignature(
sb.DoubleTypeDescriptor,
sb.DoubleTypeDescriptor,
sb.DoubleTypeDescriptor,
)
var result float64
err = sb.CallFunction(cif, mulPtr, Ptr(&result),
Ptr(new(40.0)), Ptr(new(2.0)))
fmt.Printf("multiply(40.0, 2.0) = %f\n", result) // 80.0
}
Отличия от purego
В
purego вы объявляете Go-функцию и привязываете её к C-символу через RegisterLibFunc. Это удобный и высокоуровневый подход. В speedboost всё явнее. Вы сами описываете сигнатуру через дескрипторы типов (DoubleTypeDescriptor и т.п.) и передаёте аргументы как unsafe.Pointer. Больше контроля, но больше ручной работы.Авторы
speedboost утверждают, что их подход даёт меньший оверхед на каждый FFI-вызов. Независимых бенчмарков пока нет, поэтому делать выводы о производительности стоит осторожно.Кросс-компиляция
Как и
purego, speedboost работает с CGO_ENABLED=0. Для сборки под другую платформу достаточно указать GOOS.GOOS=linux go generate ./...
GOOS=linux CGO_ENABLED=0 go run .
В примере из репозитория shared-библиотека собирается на Zig, который сам по себе хорош для кросс-компиляции. Но
speedboost не привязан к Zig — подойдёт любая библиотека с C ABI, собранная на C, Rust или чём угодно ещё.Стоит ли использовать
Если вам интересен FFI в Go без Cgo и вы хотите попробовать альтернативу
purego с более низкоуровневым API, speedboost стоит посмотреть. Особенно если в вашем сценарии критичен оверхед на каждый вызов.➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction