5 ms·
In Go, once you've FFI'd, you're likely to be able to use the Go data directly in C. In Python, you generally have to crawl over the Python-based data at Python
by jerf 2y ago
In Go, once you've FFI'd, you're likely to be able to use the Go data directly in C. In Python, you generally have to crawl over the Python-based data at Python speeds, converting it into data that your C library can understand, and then when C is done, convert it back into a Python data type at, again, effectively Python speeds. Unless you're willing for it to just be opaque data that Python effectively can route, but not manipulate. (This works, but is distinctly less useful. Of course sometimes, like for image data, it's the best option.) Combined with the sibling comment that actually times calls and finds Go is faster anyhow, even if it is a microbenchmark, I don't think your argument carries water.
It sounds to me like you've latched on to some propaganda that you like and are happy to share but don't have any personal experience with. Go's FFI is relatively slow for a compiled language, but it isn't even remotely uniquely slow. Many languages have a C FFI with some sort of relatively expensive C conversion operation, and as I point out here, that actually includes Python in many, if not most, uses (it's pretty rare to want to write code to bind to C that just ships over two integers and returns another integer or something, usually we're doing something interesting). It is the languages like Rust or Zig that can do it for effectively free that are the exception, not the rule. Go's FFI costs are not all that expensive compared to programming languages in general, and if you're worried about the FFI performance, Go also generally needs FFI less in the first place than Python because it's a fast language (not the fastest by any means, but fast), and the higher proportion of Go code will generally smoke Python anyhow. Unless you foolishly write a very tight loop of C FFI code in Go, which is a bad idea in most langauges anyhow (again excepting the exceptions like Rust and Zig), Go's going to outpace a Python program that is mostly Python but uses a bit of FFI here and there by a lot anyhow.
The idea that Go is brought to its knees by a single C call that takes 100ms or something reminds me of the people who think that as soon as you use a garbage collected language you've signed up for a guaranteed 250ms stop-the-world pause every three seconds or something. Is it free? No. Is it expensive? In relative terms maybe. In absolute terms, not really. Most programs, most of the time you won't notice, and if you are in a situation where Python is even a performance option virtually by definition you're in a situation where it won't be a problem for Go.
This is not rah-rah for Go or slagging on Python. This is just stuff engineers need to know. Python is a very capable language, but you definitely pay for it. It is not free. Every greenfield project, you need to sit down and calculate the costs and pick a good tool, but you're going to make dumb, project-killing decisions if you're using costs that are multiple orders of magnitude off of reality. I've seen it kill projects, it's not just theory.
- neonsunset 2y agoThank you for responding. Indeed, it's not quite as bad as Python in overall performance. But I'm happy it brought attention to the fact that Go is still pretty inadequate at this. My main point is engineers keep trying to shoehorn it in domains, where, should they not want to use Rust or Zig as you mentioned (which are great), they should have chosen C# (which is also great for FFI, look at Stride3D, Ryujinx or even its Sqlite driver speed, all of which are FFI heavy), but instead they keep attempting to use Go where they have to work hard to counteract its inadequacy, instead of using a platform where their solution would perform great not despite the tool but because of it.
- randomdata 2y agoThe biggest problem with FFI in Go (gc, at least) isn't in the FFI operation itself, rather FFI functions that block for a long time mess with the scheduler. It seems C# suffers the same problem as real-world benchmarks often show it to be slower than Go when performing FFI, even if it should be theoretically faster. As usual, performance can be hard to predict. Benchmarking the actual code you intend to use is the only way to ensure that what you think is true actually is. If you aren't measuring, you aren't engineering.
- neonsunset 2y agoDo you have any example of code that can demonstrate how it is possible to meaningfully slow down .NET and its threadpool and GC when performing FFI where Go does not suffer to a significantly greater extent? (if you fashion a Go example - that'll be enough and I'll make a C# one) .NET's threadpool is specifically made with the consideration of worker threads being potentially blocked in mind, and has two mechanisms to counteract it - hill-climbing algorithm that grows and shrinks the active number of threads to minimize task wait time in queues, and another mechanism to actively detect blocked threads (like system sleep or blocked by synchronous network read) and inject additional workers without waiting for hill-climbing to kick in. It is a very resilient design. Go's and Tokio threadpool are comparatively lower effort - both are work-stealing designs but neither has the active scaling mechanism .NET has already had since .NET Framework days. GC implementation at the same time is pinning-aware and can shuffle around memory in such a way to allow other objects to participate in collection or promotion to older generations while keeping the pinned memory where it is. There have been years of work towards improving this, and there is also an additional pinned memory heap for long-lived pinned allocations on the rare occasion where just performing malloc is not appropriate. I doubt there is any other high-level language or platform that can compete on FFI with .NET, something that has been considered as a part of its design since the very first version. If you want better experience your main upgrade options are literally C, C++, Zig, Rust, and honorable mention Swift (it is mostly a side-grade, with the heavy lifting done by LLVM).