Fork me on GitHub

Does anyone know what are the guarantees around ordering for putting onto a channel? Specifically, is there any difference between (go (>! ch 1)) and (put! ch 1)? Reading the implementation seems to suggest that put! should preserve ordering whereas go and >! may not?


@lfn3: They are the same under the hood. The channel guarantees that items will be delivered in the order they were put onto the channel, no matter the syntax used to put them on.


Not saying that those statements are functionally identical. They’re not. Just saying they’re identical in the way a message gets put onto ch.


I don’t know for sure, but I’ve always assumed that put! preserves ordering for all put! calls coming from the same thread.


But the >! in (go (>! could end up getting scheduled onto a different thread, so… it wouldn’t be possible to make any guarantees. It’s not even up to the channel implementation.

Alex Miller (Clojure team)15:10:26

put! goes in a queue so I agree with your expectation re preserving ordering from a thread

Alex Miller (Clojure team)15:10:45

and with your reasoning on the go >!


@alexmiller @erik_price: Yeah, there is some obvious ambiguity around ordering across threads (e.g. Two puts could happen simultaneously, so they will have to be somehow ordered in the end. Also, how the VM schedules things comes into play.), and there’s clearly a delay when spinning off a go-block vs direct put!. So when put! is actually invoked is up for grabs and very difficult to reason about. But I’ve always assumed that once put! is called, it queues things up atomically across threads. Is that incorrect?

Alex Miller (Clojure team)15:10:41

at some level, this is the nature of concurrent programming and the only thing that actually specifies the constraints for events occurring across multiple threads is the Java memory model


the original question doesn't make sense


the only one difference between the two: everything after >! inside a go block is guaranteed to happen after the put succeeds


I guess to be more clear, put! is an asynchronous put, >! is synchronous


as is >!!


@alexmiller: Yeah. Gotcha. So best answer to question 1: what erik_price said. To question 2: what ghadi said simple_smile


Cool thanks guys, that all makes sense. So the reason that order wouldn’t be preserved with a go (>! … is due to being scheduled on a different thread. We’d expect the same thing with go (put! or put! inside a raw java thread.


It’s conceptually the same thing as if you tried to coordinate the order of an update to an atom using a go block (e.g., (go (swap! some-atom …)) ).


You can do it, but you don’t get any guarantees about the order.