From what I've read/seen, the go blocks are lightweight thread-like processes multiplexed onto a thread pool. You may be correct about using Thread/sleep, ideally I would have used (timeout ...) and then pulled off the channel. However, I didn't want to introduce the concept of channels too early in the post, so I felt Thread/sleep worked as a compromise.
We will have full API and semantic compatibility when version 0.2 is released next week. Pulsar also has cluster distribution and an Erlang-like actor framework.
Because Pulsar uses instrumentation at the bytecode level, you have more freedom within Go blocks. You wouldn't use Thread/sleep in the Pulsar implementation, either, but Strand/sleep will do the job. It detects whether you're in a go block (implemented as a fiber in Pulsar), in which case it suspends the fiber but doesn't block the thread, or within a normal thread, in which case it will simply call Thread/sleep.
(time (let [c (chan), n 1000] (dotimes [i n] (go (Thread/sleep 50) (>! c i))) (dotimes [i n] (<!! c))))
"Elapsed time: 8412.25733 msecs"
(defmacro gosleep [millis] `(<! (timeout ~millis)))
(time (let [c (chan), n 1000] (dotimes [i n] (go (gosleep 50) (>! c i))) (dotimes [i n] (<!! c))))
"Elapsed time: 91.278469 msecs"
ETA: for comparison, here's what happens if you actually make 1000 system threads:
(time (let [c (chan) n 1000] (dotimes [i n] (thread (Thread/sleep 50) (>!! c i))) (dotimes [i n] (<!! c))))
"Elapsed time: 4183.669835 msecs"
This is an awesome post, thanks for it ^_^
If you perform a blocking operation (Thread/sleep there, but could be, for example, a socket read?) will you run the risk of exhausting the thread pool?
The go runtime handles this by detecting how many threads are in blocking syscalls and spawning more as needed (which I guess could be undesirable).
If I've understood correctly, this is perhaps best summarised as "go makes your sync code run well in goroutines, with core.async you can block everything with sync syscalls in your go block"?
Or perhaps just "go will adjust the size of your thread pool dynamically, core.async requires it to be big enough"