Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure core.async put! versus go block

I've read this great article about core.async here:

http://www.core-async.info/reference/primitives

I'm struggling to understand the internal mechanic of put! and go. I understand that:

  1. put! is asynchronous and can accept a callback. That works well in simple scenarios, but you can end in a callback hell.
  2. go fixes the callback hell, and allows to write asynchronous code in a synchronous style.
  3. go leverages a lightweight thread-pool, and leverages parking to enable concurrency.
  4. go uses a finite state-machine

I don't understand:

  1. How does put! achieve asynchrony? Does it also uses a thread-pool?
  2. Does put! also uses parking?
  3. What is the role of the finite state-machine in the go block? Is it what enables parking?
  4. Should I always try to use put! rather than go because it is cheaper? In that case, does that mean that put! achieve the exact same concurrency goodness as go, and that go is only used when I want to reason about complex asynchronous code?

Thanks a lot for shedding the lights on those mysteries.

like image 225
Nicolas Dao Avatar asked Feb 11 '16 14:02

Nicolas Dao


1 Answers

If you want to understand how core.async channels work, there's no better source than Rich Hickey's EuroClojure 2014 presentation: Implementation details of core.async channels.

As for your specific questions:

  1. If put! is not accepted immediately, it places a pending put (the value to be put on the channel + the put! callback) on a queue internal to the channel. Note that an exception will be thrown if there is no room in the queue (max capacity is currently fixed at 1024).

    The callback will be called on a pooled thread if (1) the put is not immediately accepted or (2) an explicit false is passed in as a final argument to the put! call (this argument is called on-caller?, see put!'s docstring for details).

  2. "Parking", in the context of go blocks, refers to suspending execution of a go block's state machine by recording certain details of its current state and saving them inside a channel, or possibly several channels, so that it can be restarted later. (Note that this arrangement means that if all the channels holding references to a suspended go block are GC'd, the go block itself can also be GC'd.) In other contexts it similarly refers to putting a thread of control in a state of suspended animation. put! is just a function (well, it's backed by a protocol method, but then that is just a protocol method), so the concept doesn't apply.

  3. Yes. It basically steps through the code in the go block, possibly suspending it when control reaches certain "custom terminals" (<!, >!, alt!).

  4. Not necessarily, you should first consider the risk of overflowing the internal queue (see point 1 above).

like image 101
Michał Marczyk Avatar answered Sep 21 '22 19:09

Michał Marczyk