Crowbar central

A blog about the ooc language, with source code examples, updates on the state of the llama (our beloved mascot), and random thoughts by nddrylliog, the benevolent dictator for life of ooc.

The opinions expressed in this blog are not necessarily those of the whole ooc community.

Jul 22

Channels and Coroutines in ooc

Hey there, tumbr’ling directly from OSCON, watching Mr. Shapiro talk about BitC.

So I watched Rob Pike’s talk (of Limbo/Go fame) about CSP, and Steve Dekorte (of Io fame) told me: “I wonder if it couldn’t be done simply as a library for an existing language”

So, I hereby present you ooc-channels. It steals its API right-out from the Go language.

The go() function takes a closure and allows you to start a Coroutine doing stuff. Since the closure can access the outer context, you can access…

Channels! Which are created using the make() function, which takes a type (really, a class) as an argument. No special syntax. Just goodness.

And two operator overloads to make this nice: sending a message is: channel « message, and receiving from a channel is: ! channel

Here’s a small example:

chan := make(Int)
go(|| for(i in 0..100) { chan « i }) 
go(|| while(true) { i := !chan; i toString() println() }) 

Nice, right? There’s a more complete ‘sieve’ example in the repo, again totally a rip-off from the Go website examples (which is pretty convenient).

There are two implementations in ooc-channels currently: ThreadedChannel, which starts one thread for every go() call, and CoroutineChannel, which uses one OS thread and one coroutine for every go() call with a trivial coroutine scheduler that runs on every send/recv call to Channel (ie. «, !).

The ThreadedChannel implementation works fully in parallel, but stalls at ~2600 concurrent channels on my machine (probably because of the max number of threads imposed by the OS - could be tweaked, but still insane).

On the other hand, the CoroutineChannel hits hard limits of the GC itself! With a Boehm GC compiled with -DLARGE_MODEL, I have been able to launch 86’000 concurrent channels before it dies because there are too many root sets (look up the implementation if you want more details). Again, can be tweaked, but there’s probably a better solution (e.g. using the GC_push_roots hook, which I don’t know how to do.)

The implementations is obviously not of the quality of the Go language (although I haven’t verified that) but it’s fun to see what one can come up in 24h =)