On Sun, Nov 15, 2009 at 02:24:41PM +0100, frederic wrote:
Be careful what you say. None of those features necessarilly sacrifice efficiency. In fact, garbage collection can be a huge performace boon when implemented properly, in that garbage can be lazily freed in hunks and with minimal locking.

Compared to your grand-daddy's GC? Obviously yes. But no GC language has yet prevailed against C in benchmarks.

I don't have any statistics, but I'm not so sure of that. At least, as I said, depending on the use case. Heavily multi-threaded and dynamic memory intensive code takes a huge hit in locking for every malloc, and garbage collectors have a lot to gain by managing their collection in batches. I'm fairly certain that I can find benchmarks to the contrary.

Beyond that, there are cases like the Dis vm, which uses ref counting with a low priority, real-time, non-locking GC to clean up cycles. Automatic ref counting has no performance drawbacks over manual ref counting, and the GC has virtually no impact on performance otherwise.

Interfaces and packages are free, as far as performance is concerned, though implementations may vary.

It seems to me that there's virtual tables behind interfaces, which means one level of indirection.
It may be cheap compared to the provided facility, but it's not free.

That's an implementation detail. In principal, they're not necessary. And it very much depends on what you're comparing them to. It's fairly common for C code to provide structs of function pointers, and this is no different. Namespaces require nothing more than symbol mangling.

C strings are slow when you need to get their length.

It's not a win-all situation. Immutable strings may be more expensive in some use cases. Furthermore, they either have to convert back to zero-terminated strings when passing them to libs, or use the trick of appending ("quand même") a zero byte, which is redundant wrt to the array lenght.

Well, you didn't exactly elaborate on "strings". C provides both mutable and immutable strings, and I imagine that Go provides the same, too (although it would probably call the former byte arrays). There's no issue with passing them to libs, since Go uses its own libs. The C code it might interface with is a different (and irrelevant, given that the same issue presents itself in any language-to-language interface) issue.

Closures needn't be any more expensive than any other kind of function reference,

One has to pass at least an extra parameter, which is a pointer to the captured values. It is always more expensive than passing a pointer to a function.

First of all, nearly every interface in C which accepts function pointers also accepts a data pointer to pass context information. Even in the cases that don't, the difference is negligable. With the convention that each function pointer is passed always passed with one function and one data pointer, as far as performance is concerned you've incurred only one extra machine instruction per assignment, or each time the function is passed, once per each call to the function, plus the size of one pointer in memory consumption (and possibly any ref counting overhead, depending on the implementation). With the convention that a pointer to the struct is passed, the only performance hit is one extra machine instruction during the function call, and again possibly any memory management overhead, plus the memory of two pointers and whatever other memory overhead such structures incur. Given that those instructions are utterly dwarfed by the cost of a function call, the difference is not worth mentioning unless you're passing tens of them per function call. I'll admit, though, that without the restriction that a closure is only valid along with the current stack frame, closed over variables are forced into heap allocation, but again it's no loss over other methods.

All this is more than just nit-picking. Pike claims a 10-20% loss compared to C, which would still be quite good.

Yes, there's certainly overhead compared to C, but I really doubt that it had much if anything to do with the features you mentioned. Type and bounds checking is expensive. Pointer arithmetic is very cheap. Plus, it's very easy to decide what is heap and what is static or stack allocated in C, and I very much doubt that to be the case in Go (yes, I'm citing memory management issues other than GC).

--
Kris Maglione

It should be noted that no ethically-trained software engineer would
ever consent to write a DestroyBaghdad procedure.  Basic professional
ethics would instead require him to write a DestroyCity procedure, to
which Baghdad could be given as a parameter.
        --Nathaniel S. Borenstein


Reply via email to