在GoLang应用程序中使用C(++)来提高性能

时间:2016-06-22 06:44:11

标签: c++ c go gccgo

我几天前就开始学习Go了,来自CGO的东西和gccgo编译器。根据我的理解,这允许使用Go编译器编译Go程序并使用C编译器编译C库并从Go程序内引用这些库。这对我来说真的很有意思,因为这样我们可以在主程序中利用C的性能(如果需要)而且开销很小。

但是我不确定那是多么的少,所以我在这里问:

是否有创建C库的情况只是为了在Go应用程序中使用它?或者此功能仅用于促进现有C代码的重用性?

P.S:我认为目前CGO不支持C ++,但是有人发表了一篇能够使用C函数包装C ++代码并成功调用它们的帖子。

2 个答案:

答案 0 :(得分:10)

Cgo相当慢,因为Go必须以mess with its runtime and calling conventions以某种方式调用C函数。它真正值得的唯一地方是计算时间明显相形见this cost的情况。它类似于并行,分布式,GPU等编程,虽然启动成本略低。

汇编要好得多,因为你可以编写使用Go的调用约定的程序集,并且在其他方​​面被视为本机Go代码,但程序集的可移植性较差,难以阅读,维护较多。事实上,Go标准库在Plan 9风格的程序集中编写了一些mathbig包。

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 ++实践更安全的东西。

答案 1 :(得分:1)

除非C库在一次调用中完成大量工作,否则我不会仅仅为了性能而编写C代码。我认为cgo仅用于与旧代码接口。

原因是cgo开销。目前对cgo函数的函数调用是between 50 and 100 times slower than function calls to Go code。 cgo函数调用的开销令人震惊。