Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C(++) in a Go application for performance

Tags:

c++

c

go

gccgo

I've started studying Go a couple of days ago and came by its CGO thing and the gccgo compiler. From my understanding this allows a Go program to compile using the Go compiler and compile C libraries using a C compiler and reference those libraries from inside a Go program. This is really interesting to me because this allows us to leverage C's performance (if needed) from our main program with little overhead.

However I'm not sure how little that is, so I'm asking here:

Are there cases where you would create a C library just to use it from inside your Go application? Or is this feature only to facilitate re-usability of existing C code?

P.S: I think at the moment CGO doesn't support C++ but there was a post here of someone that was able to wrap C++ code using C functions and call them successfully.

like image 727
PentaKon Avatar asked Jun 22 '16 06:06

PentaKon


People also ask

Is Golang as fast as C?

Golang can boast speeds of close to four times quicker than it's interpreted and dynamic friends. That said, very little can touch C++ (and most C languages) when it comes to speed. All of the time spent coding and compiling pays off here.

Does Go use C?

Go does not require any C libraries if that's what you're asking.

Can you use C libraries in Go?

Go allows linking against C libraries or pasting in in-line code.

How much slower is Go than C?

In these results Go is generally half the speed of C, but 50 times faster than python.


2 Answers

Cgo is fairly slow, because Go has to mess with its runtime and calling conventions in certain ways to call C functions. The only place it's really worth it is cases where the compute time significantly dwarfs this cost. It's similar to parallel, distributed, GPU and so on programming, albeit with slightly lower startup costs.

Assembly is much better, because you can write assembly that uses Go's calling convention, and is otherwise treated like native Go code, but assembly is far less portable, harder to read, and more maintenance heavy. In fact, the Go standard library writes some of the math and big packages in Plan 9-style assembly.

Gonum is an example of both of these. It uses common assembly for some functions that can be done more quickly that way, but it also leverages blas and lapack engines. It does provide a Go-blas implementation, but C-blas (which is usually ultimately Fortran-blas) is faster, and for large matrix computations almost always dwarfs the cost of leaving Go.

Generally, you want to avoid cgo when possible. Only use it when significant computation time is needed, or you need to interact with things that would be non-trivial to interact with in pure Go, such as graphics or audio drivers, or accessing common libraries like OpenCV. Even then, if you really care about performance, where possible it may be worth it to implement some sort of "call pooling" where you can schedule multiple calls from the Go side and execute them all at once with a single context switch to C.

Edit: As for C++, there are some significant issues. It can be difficult to wrap certain libraries without several layers of abstraction (since cgo cannot handle included C++ headers properly). In addition, C++ classes with destructors can't really be returned by value and have to be allocated on the heap. Since Go doesn't allow for deterministic finalization of resources, you must provide a function to explicitly free memory, and the Go user must remember to free the resource. (There is a function you may read about in the documentation called runtime.SetFinalizer but I can't say I've ever seen anyone use it, and the documentation itself comes with a bunch of caveats)

Functionality such as defer makes this more manageable, but it ruins a lot of things like RAII which make modern C++ practices safer.

like image 140
Linear Avatar answered Oct 21 '22 23:10

Linear


Unless a C library does a lot of work in one call I wouldn't write C code just for performance. I consider cgo to only be for interfacing with old code.

The reason is the cgo overhead. Currently function calls into cgo functions are between 50 and 100 times slower than function calls to Go code. The overhead of cgo function calls is shocking.

like image 45
Art Avatar answered Oct 22 '22 00:10

Art