Go Concurrency Patterns ported to Clojure
gist.github.com
gist.github.com
Doing blocking operations inside a go is a anti-pattern.
Sorry - could you elaborate please?
In my understanding, in golang it's fine to block a goro with a blocking call, whether that be a blocking syscall (read/write/sleep) or a blocking read from/write to channel (perhaps multiplexed with select).
The scheduler will run other goros on the threadpool until the blocking call finishes. That's the "secret sauce" which allows you to write synchronous code in go without single-thread-per-goro (and requires a runtime to arbitrate the system calls and schedule goros)
Code inside (thread) blocks run on a dedicated thread. This allows for long running or IO bound processes to execute without clogging the main thread pool. Thread blocks do not rewrite their bodies into a state machine (unlike go blocks) and as such must use <!! and >!!. Since these threads are dedicated they do not return the thread to the thread pool when blocking. This allows for slightly better performance at the cost of an entire JVM thread for the life of the block.
TL;DR - Use <! and >! with go. Use <!! and >!! with thread. Mixing the two can have very unexpected results. In fact, using <! inside a thread block will result in a runtime exception.
Yes - this seems to be a key difference of golang's approach. The runtime+scheduler conspire to make a blocking goro much cheaper than an OS thread.
By "know" I mean something like an in-go earmuff var.
EDITED for clarification and formatting
Part of it obviously does since `<!` can't be called outside of a go block. And cljs has somewhat less of an issue there as it does not have `<!!` (since without extension the language has very little allowances for blocking)
The distinction is that it's not go, `go` blocks are macros doing a bunch of transformations. `<!` and `<!!` have the same purpose (get a value from a channel) but not the same context, `<!` can only be called inside a (go) block and will be transformed into a parking of the thread (yielding to the runner), whereas `<!!` works at a lower level and will block their whole thread.
> The scheduler will run other goros on the threadpool until the blocking call finishes.
`<!!` and the coroutine scheduler are not aware of one another, calling `<!!` from within a coroutine will block the scheduler. `<!!` (and `>!!`) exist specifically to be called from outside the scheduler (from outside a `go` block)
Likewise, `Thread/sleep` is not aware of the coroutine scheduler (it would have to be monkey-patched), calling it will also block the scheduler itself. core.async provides `timeout` for the purpose of parking a coroutine.
Simplicity doesn't always mean "one" it means decoupling related ideas. Sometimes simpler means more things that each do one thing.
Notice how Clojure has refs, atoms, vars, and agents. Each does something completely different, each with its own tradeoffs and bonuses. Coupling reduces flexibility by throwing all the tradeoffs (often with additional issues) into one large pile.
So I see core.async as being inline with the Clojure ideals. Pull things apart and offer only simple primitives that can be combined to create larger systems.
They both block the thread and any other go-blocks that happen to be mapped to it. I think you get 2 x NUM_CPU threads in the dedicated pool for channels, so either of these is a mistake. (Aside: I'm not sure why you were down voted for saying this.)
When you need to wait inside of a go-block, the correct way is to use (timeout millis), which creates and then closes a channel.
This has some nice examples: https://github.com/clojure/core.async/blob/master/examples/w...
But actually, Pulsar's main advantage is that it's simply a Clojure API for Quasar (https://github.com/puniverse/quasar), which adds all of these capabilities to Java and any other JVM language by providing true lightweight threads. core.async's advantage is that it can also be used in ClojureScript, while Pulsar only works on the JVM.
EDIT: I bring this up because this seems like a common misstep for users of core.async, and a simple pattern for blocking IO might help people avoid it.
core.async really looks awesome...if we can create simple patterns for working with blocking operations, it would be a compelling model for a lot of use cases.
(Also, hats off to the core.async developers; it seems like the reward for creating something great is just demand for more. ;)
The next step is deciding on how to expose the asynchronicity. I chose to accept / return channels rather than callbacks, because... well... wrapping your sync code in a callback-based async API just to glue them together with go blocks and channels seemed backward to me. :)
I think this "next level up" from the foundation of core.async has potential for some really great solutions and I'm dying to see what Tim and others will come up with...
I didn't mean to misrepresent core.async. I just heard about it one day and got compelled enough by a walkthrough[1] to convince myself I could figure enough of it out to make something happen in my nrepl buffer. Which happens to also describe my approach to life now that I think about it. Except, you know, in my life buffer.
[1]: https://github.com/clojure/core.async/blob/master/examples/w...