PureGo(ebitengine/purego) vs GoFFI(go-webgpu/goffi)完整对比 (数据截至 2026 年 3 月 16 日最新状态)
两者都是纯 Go、无 CGO 的 FFI 库,目标相同:CGO_ENABLED=0 就能调用任意 C 动态库(.so/.dll/.dylib)。但设计哲学、API 风格、性能侧重完全不同。
| 项目 | PureGo (ebitengine/purego) | GoFFI (go-webgpu/goffi) |
|---|---|---|
| GitHub | github.com/ebitengine/purego | github.com/go-webgpu/goffi |
| Stars | ≈ 3.5k | ≈ 30(极小众) |
| 最新版本 | v0.10.0(2026.2) | v0.4.2(2026.3) |
| 起源 | Ebitengine 游戏引擎团队(通用绑定) | GoGPU/WebGPU 项目(GPU 计算专用) |
| 成熟度 | 高(Tier 1/2 广泛支持,已用于 chdb、GTK、libvips 等) | 中(专注 WebGPU,仍在快速迭代) |
1. 设计思想对比(Design Philosophy)
- PureGo:“像写 Go 代码一样调用 C”
- GoFFI:“像 libffi 一样极致性能 + 完全 ABI 控制”
一句话总结:PureGo 是“生产力工具”,GoFFI 是“极致性能引擎”。
2. 架构设计对比
- PureGo:
- 高层:
RegisterFunc+reflect.MakeFunc动态生成 wrapper。 - 中层:
fakecgo(完整复制 Go runtime/cgo 栈切换、callback)。 - 底层:平台/架构特化汇编(dlfcn_*.s、zcallback_*.s),参数用
syscall15Argspooled。 - 自动处理字符串、bool、slice。
- GoFFI:
- 高层:
LoadLibrary+GetSymbol+PrepareCallInterface(CIF)。 - 中层:
types.TypeDescriptor(手动描述 Size/Alignment/Kind)。 - 底层:手写汇编 trampoline(每个进程预编译 2000 个入口,AMD64 仅 5 字节!)+
crosscall2(C 线程回调)。 - 显式 ABI 控制(RAX+RDX、sret、XMM0、AAPCS64 HFA 递归检测)。
3. 性能对比(官方数据)
GoFFI 在 README 公开 benchmark(Intel i7-1255U,AMD64):- 单次调用开销:88~114 ns(getpid 88ns,strlen 98ns,abs 114ns)。
- 每调用零分配(CIF 可复用)。
- 60 FPS × 50 调用/帧 = 仅 5µs/帧(占帧预算 0.03%)。
- 使用
sync.Pool+ reflect → 每调用 1~2 次 alloc,开销更高(约 150~250ns)。 - GoFFI 在 GPU 热路径上通常快 30%~50%。
4. 功能支持对比(核心表格)
(直接来自 GoFFI README + 2026.3 DEV.to 文章)| 特性 | PureGo | GoFFI | CGO |
|---|---|---|---|
| API 风格 | reflect RegisterFunc(一行注册) | libffi 风格(Prepare CIF → CallFunction) | 原生 |
| 每调用分配 | 有(pool) | 零 | 零 |
| 结构体传参/返回 | 部分(Windows 弱) | 完整(RAX+RDX、sret) | 完整 |
| 回调返回 float(XMM0) | panic | 支持 | 支持 |
| ARM64 HFA(嵌套浮点结构体) | 部分 bug | 完整递归检测 | 支持 |
| 字符串/切片自动转换 | 优秀(自动 null + KeepAlive) | 仅 raw pointer(需手动) | 优秀 |
| Context 超时/取消 | 无 | 支持(CallFunctionContext) | 无 |
| C 线程回调 | 支持 | 支持(crosscall2) | 支持 |
| 平台覆盖 | 8+ GOARCH / 20+ OS | 6 核心(Win/Linux/macOS × amd64/arm64) | 全 |
| Typed Error | 泛型 error | 5 种强类型 + errors.As | N/A |
| Variadic 函数 | 支持 | 暂不支持(v0.5 计划) | 支持 |
5. 使用示例对比(strlen)
PureGo(简单):lib, _ := purego.Dlopen("libc.so.6", purego.RTLD_NOW)
var strlen func(unsafe.Pointer) uint64
purego.RegisterLibFunc(&strlen, lib, "strlen")
fmt.Println(strlen(unsafe.Pointer(unsafe.StringData("hello\x00"))))
GoFFI(显式但更快):
handle, _ := ffi.LoadLibrary("libc.so.6")
sym, _ := ffi.GetSymbol(handle, "strlen")
cif := &types.CallInterface{}
ffi.PrepareCallInterface(cif, types.DefaultCall, types.UInt64TypeDescriptor,
[]*types.TypeDescriptor{types.PointerTypeDescriptor})
var length uint64
strPtr := uintptr(unsafe.StringData("hello\x00"))
ffi.CallFunction(cif, sym, unsafe.Pointer(&length), []unsafe.Pointer{unsafe.Pointer(&strPtr)})
6. 优缺点总结
PureGo 优势:- 代码最少、最易上手
- 字符串/slice 自动处理
- 平台支持最广(含 ppc64le、riscv64、s390x)
- 社区生态成熟
- 性能碾压(零分配 + 更优 ABI)
- 复杂结构体、浮点回调、ARM64 HFA 更强
- Context 支持、typed error、更安全
- 专为 GPU/WebGPU 设计(wgpu-native 官方绑定)
7. 适用场景推荐
- 选 PureGo:普通绑定(libpng、SDL、GTK、数据库、插件系统)、需要多平台、追求开发速度的项目。大多数开发者首选。
- 选 GoFFI:GPU 计算、WebGPU、实时渲染、ML 推理、高频循环调用(>10万次/秒)、对结构体/浮点回调有强需求。GoGPU 项目已全面采用。
- 两者共存:可行,但注意 linker 冲突(用 build tag 分离)。
结论: PureGo = 生产力王者(3.5k stars 证明一切) GoFFI = 性能王者(GPU 场景必备)
如果你是做游戏/图形/AI 推理,强烈推荐试 GoFFI;普通系统集成,继续用 PureGo 就够了。
Repo 链接:
- PureGo:https://github.com/ebitengine/purego
- GoFFI:https://github.com/go-webgpu/goffi (带详细 PERFORMANCE.md)