cgo 是 Go 与 C 代码交互的桥梁。通过 cgo,Go 程序可以调用现有的 C 库,也可以让 C 代码调用 Go 函数。但这把双刃剑使用不当会显著增加复杂度和性能开销。
基础用法
/*
#include <stdlib.h>
#include <stdio.h>
*/
import "C"
import "unsafe"
func main() {
cs := C.CString("Hello from C")
defer C.free(unsafe.Pointer(cs))
C.puts(cs)
}
cgo 的开销
调用 cgo 函数不是简单的函数调用——它涉及 goroutine 栈切换、M 与 P 的调度以及 C 线程和 Go goroutine 之间的上下文切换。一次 cgo 调用的开销大约是普通 Go 函数调用的数十倍。
内存管理注意事项
- Go 的 GC 不管理 C 分配的内存,必须手动调用 C.free。
- C.CString 会在 C 堆上分配内存,必须释放。
- 不要让 Go 指针在 C 代码中持久存储(Go 1.6+ 的 cgo 指针规则)。
替代方案
在考虑 cgo 之前,先评估是否有纯 Go 的替代方案。如果只需要调用几个系统调用,syscall 包或 golang.org/x/sys/unix 可能就够了。许多流行的 C 库已有纯 Go 实现。
cgo 是通往 C 世界的桥梁,但不是免费的——每一次跨越都有代价。