|
|
Subscribe / Log in / New account

Van Rossum: Python is not too slow (InfoWorld)

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 9:06 UTC (Tue) by cmccabe (guest, #60281)
In reply to: Van Rossum: Python is not too slow (InfoWorld) by Cyberax
Parent article: Van Rossum: Python is not too slow (InfoWorld)

Ok, people have been bugging me about Rust for long enough. So I'm actually going to compare Rust and Go somewhat. Looking at the FAQ (from http://www.slideshare.net/pcwalton/rust-all-hands-winter-...), it seems like Rust made a few interesting decisions that differ from Go. Keep in mind that I am writing this in early 2012, and things may change. Everything here is current to the best of my knowlege.

Allocation: Rust has three different types of allocation -- "interior types" which are stored on the stack, "unique types" which are scoped, and "boxed types" which are GC'ed. Go only has one type of allocation and the compiler figures out what to do for you. Go does have the "defer" statement, which you can use to get something very like C++ scoped destructors or Rust "unique types." This somewhat reflects the C++ background of the Rust developers. C++ has always given you lots of different flavors of allocation. Is this a good thing? Um... for a high-level language, probably not.

Rust goes through great lengths to avoid global garbage collection. Go currently has a stop-the-world garbage collector. I think this reflects the fact that Mozilla, with their interest in big, user-interface intensive programs, developed Rust, whereas Google, with their interest in server stuff, is backing Go. I don't think this is a big long-term problem for Go. Google has shown us with Dalvik and V8 that incremental garbage collectors are a practical way to solve this problem.

Both Rust and Go have structural subtyping. Go has a very intuitive system for creating modules and encapsulation (in my opinion.) I'm not as familiar with Rust's systems in these areas, so I can't comment on them. Both Rust and Go provide mechanisms to structure programs in terms of many small tasklets that share state by communicating rather than with mutexes, locks, and shared state.

As mentioned above, Rust has this concept of immutable data, which Go lacks. In Rust, mutable data needs to be allocated in a special way, on a special heap (all other data is immutable.) Currently there is a flaw in the Rust type system which allows supposedly immutable data to be modified, but hopefully this will soon be fixed. [ See https://github.com/mozilla/rust/wiki/Proposal-to-address-... ] You can get most of the benefits of immutable data in Go by passing around values rather than pointers. (In Go, channels can take either values or pointers.) It is good to avoid gratuitous mutation, but I find myself wondering whether the Rust approach will be clunky in practice.

I've suffered through a lot of pain being "helped" by the C++ type system, which forbids, for example, passing a vector<char*>* to a function which expects vector<const char*>*. So I am a little bit gun-shy of trying to enforce these types of things through a complex type system. For now, I'll just say this: time will tell if Rust's approach is viable.

Rust also disallows null pointers, which I personally do not agree with. Maybe it's my background as a C programmer, but I like having a special value to represent "none." I always find myself using clunky workarounds to emulate NULL when it is not present in the language-- especially in languages without exceptions (but more about that later.)

Rust has generics, and Go does not. The creators of Go have publicly stated that generics might be added in the future, but nobody has a timeframe. Generics are probably the thing that I most miss in Go.

Both Rust and Go try to encourage you NOT to use exceptions as a control flow mechanism. Rust has "fail," and Go has "panic," but neither of them is a traditional exception mechanism like you might find in Java. They don't allow you to associate much with the exception except a string. This seems like a good choice to me-- flow control via exceptions is icky. It will surprise some people, though.

Rust has this concept of "typestate," which is kind of like the Linux kernel's BUILD_BUG_ON or Boost's static_assert, but built-in. This is something that I really like. Things like this can be retrofitted on to the language after the fact-- like sparse does for C, or annotations do for Java-- but it is better to put it to the compiler itself.

Language change: Rust has changed a lot from 2010 to 2011, and seemingly in backwards-compatibility breaking ways. Even the syntax changed a lot. This reflects a lack of actual users and a more academic attitude. Will Rust finally stabilize in the future, or keep ever-changing like D has? Hopefully the former.

Code maturity: The Rust slide deck from late 2011 says "we're missing garbage collection... and the compiler isn't yet production-quality." (This is a direct quote from the slide deck-- please don't flame me about this.) So it seems irresponsible to point people looking for something to use in production towards Rust, until those points are fixed. On the other hand, Google is using Go in production right now.

I hope I've been fair here!
cheers, C.


(Log in to post comments)

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 10:10 UTC (Tue) by khim (subscriber, #9252) [Link]

Google has shown us with Dalvik and V8 that incremental garbage collectors are a practical way to solve this problem.

What Google actually showed is that RFC 1925 is still in effect: while GC is totally unsuitable for UI (that's why company which knows how to create attractive UI deprecates it), but yes, if you'll spend enough time with profiler and if your system is powerful enough (say, 10x as powerful as the task on hand really needs) then GC may work for UI. It remains to be seen if Go will actually be ever usable for UI.

Rust has changed a lot from 2010 to 2011, and seemingly in backwards-compatibility breaking ways.

Go did that too. This is not a crime: C++, for example, introduced a lot of backward-incompatible changes in it's early days. Only years after introduction (when there was already huge amount of code written) it stopped doing this. And C++11 introduces breaking changes again.

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 13:02 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link]

Rust has been produced specifically to minimize the need for garbage collection and the impact of the collector. Once one understands this, the design decisions for Rust become completely clear and intuitive.

Unique types allow deterministic destruction of resources - you are guaranteed not to have memory/resource leaks with them. Unfortunately, the next step (refcounted handles) can not make such guarantees. So they've stopped at unique types.

Dividing the RAM into independent thread-local heaps helps immensely - Erlang does it for exactly the same purpose, for example. Experience has taught us that truly pauseless 'global' garbage collectors are possible, but they either have a big overhead or require hardware assists (there's a company that even creates special hardware for high-speed GCs!).

The split between immutable and mutable types in Rust is interesting. But I don't think it can be simplified much. And no, Go doesn't have anything like it - you can pass mutable data using channels (which is actually an advantage in Go's programming style).

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 18:17 UTC (Tue) by njs (guest, #40338) [Link]

IIUC, the fundamental difference between Go and Rust is that both make multi-threading a core feature of the language, but Go threads are shared-everything and Rust threads are shared-nothing. (Or very roughly in C terms, Go threads act like pthreads, and Rust threads act like fork.) Go encourages you not to program in a style where your threads stomp on each other's data-structures willy-nilly, but there's no protection built into the language itself. OTOH, AFAICT Rust doesn't even *have* mutexes, because it has safer ways to share state.

Personally this difference is enough to pretty much rule out Go as an option so long as Rust ends up being viable at all, no matter what other clever syntax and type systems and stuff they have... but of course YMMV.

> Rust also disallows null pointers, which I personally do not agree with. Maybe it's my background as a C programmer, but I like having a special value to represent "none." I always find myself using clunky workarounds to emulate NULL

I don't remember the details, but I'm pretty sure it's easy and idiomatic in Rust to define a "maybe<X>" type: a value which is either "none" or else has a real pointer-to-X in it. The trick is that unlike C, now you *can't* dereference such a pointer without checking for NULL-ness when "unpacking" it. This might seem like a burden, but of course it only applies to those pointers which *might* be NULL, which are exactly the ones that you have to check. So they're not trying to make this clunky; basically it's just like C, except now the compiler will keep track of when you need to check for NULL and when you don't. Boom, no more segfaults.

> Rust has this concept of "typestate," which is kind of like the Linux kernel's BUILD_BUG_ON or Boost's static_assert

Typestates are *substantially* more powerful than BUILD_BUG_ON, because typestates make compile-time assertions about program flow. A simple example of a typestate assertion would be "strings which come from the network and then later end up being passed to the filesystem *must* go through the utf8 sanitizer at some point in between". If you accidentally add a code path that violates this invariant, the compiler will tell you.

Generally a lot of things in Rust are designed around the idea a good language should help you write correct code.

(Disclaimer: Graydon's a friend, and I reviewed an early version of the Rust spec, but I haven't been involved or followed the project much since.)

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 19:24 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link]

To be fair, shared-everything concurrency can be much more efficient than shared-nothing message passing in certain tasks (just look at those RCU articles!).

So I'd certainly like at least some controllable amount of sharing with explicit locking. But message-passing seems to be much easier to write for.

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 20, 2012 20:10 UTC (Tue) by njs (guest, #40338) [Link]

RCU doesn't imply shared-everything, just shared-a-few-things-under-very-carefully-controlled-conditions :-). There's nothing stopping them from adding an experts-only, carefully-bounded escape hatch in the standard library. Or from using RCU under the covers to implement something with those semantics -- Rust doesn't literally use 'fork', language runtimes can be very tricky about how they implement things. OTOH you can't add memory isolation in a library :-).

But yeah, it's possible that in some situations, code in Rust will be slower than the best possible concurrent implementation that exploits details of the CPU's cache coherency model etc. For me this is a totally acceptable trade-off, but again YMMV.

(Anyway, it doesn't look like Go has any primitive memory barrier operations, so your only safe concurrency options there are mutexes and channel sends. No RCU.)

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 21, 2012 16:36 UTC (Wed) by cmccabe (guest, #60281) [Link]

Golang has atomic operations, which imply memory barriers, and also pointers. See http://golang.org/pkg/sync/atomic/ This is something that actually exists now, not just in theory.

As far as I can see, you should be able to use the CompareAndSwapUintptr operation to get the update-side memory barrier you need for RCU. Then you should be able to have reader threads read the pointer value normally, without a memory barrier, and get whatever they get.

In Go, you have garbage collection, so you can forget all about fooling with grace periods and so forth. Just update the pointer.

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 21, 2012 16:53 UTC (Wed) by khim (subscriber, #9252) [Link]

In Go, you have garbage collection, so you can forget all about fooling with grace periods and so forth. Just update the pointer.

Not exactly. Quite often things like RCU are used for performance-critical tasks. The fact that language is built around GC means that now you not only need to worry about grace periods but you must convince GC to [roughly] obey them.

YMMV: in some cases it may all “just work”, in some other cases you'll spend huge amount of time taming GC (and then everything will break once GC will be changed in your implementation).

In fact non-optional GC is my biggest gripe with go.

Van Rossum: Python is not too slow (InfoWorld)

Posted Mar 21, 2012 17:05 UTC (Wed) by njs (guest, #40338) [Link]

Ah, thanks! I missed those because they aren't mentioned on the Go memory model page: http://golang.org/doc/go_mem.html


Copyright © 2023, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds