Cgo 相当慢,因为 Go 必须以某些方式扰乱它的运行时和调用约定来调用 C 函数。唯一真正值得的地方是计算时间显着使成本相形见绌的情况。它类似于并行、分布式、GPU 等编程,尽管启动成本略低。
汇编要好得多,因为您可以编写使用 Go 调用约定的汇编,并且在其他方面被视为本机 Go 代码,但汇编的可移植性要低得多,更难阅读,维护也更繁重。事实上,Go 标准库以 Plan 9 样式的程序集编写了一些math
和big
包。
Gonum就是这两者的一个例子。它对一些可以通过这种方式更快完成的功能使用通用程序集,但它也利用了 blas 和 lapack 引擎。它确实提供了一个Go-blas
实现,但是 C-blas(通常最终是 Fortran-blas)更快,并且对于大型矩阵计算,几乎总是使离开 Go 的成本相形见绌。
通常,您希望尽可能避免使用 cgo。仅在需要大量计算时间时使用它,或者您需要与在纯 Go 中无法进行交互的事物进行交互,例如图形或音频驱动程序,或访问 OpenCV 等通用库。即便如此,如果您真的关心性能,那么在可能的情况下实现某种“调用池”可能是值得的,您可以在其中安排来自 Go 端的多个调用,并通过单个上下文切换到 C 来一次执行它们。
编辑:至于 C++,有一些重大问题。如果没有几个抽象层,可能很难包装某些库(因为 cgo 无法正确处理包含的 C++ 头文件)。此外,带有析构函数的 C++ 类不能真正按值返回,必须在堆上分配。由于 Go 不允许资源的确定性终结,因此您必须提供显式释放内存的函数,并且 Go 用户必须记住释放资源。(您可能会在名为的文档中读到一个函数,runtime.SetFinalizer
但我不能说我见过有人使用它,而且文档本身带有很多警告)
诸如此类的功能defer
使这更易于管理,但它破坏了许多诸如 RAII 之类的东西,这些东西使现代 C++ 实践更安全。