asynchronousclojurecore.async

Clojure async - Order of items in a channel


I'm having some difficulty understanding the output of the following code sample.

(def ch (a/chan 1))

(a/go-loop []
  (Thread/sleep 1000)
  (a/onto-chan ch [1 2 3 4 5] false)
  (recur))

(a/go-loop []
  (Thread/sleep 500)
  (let [val (a/<! ch)]
    (println val))
  (recur))

What I expected to see was a 500ms delay between each number that is printed to the REPL, receiving the numbers 1-5 in order before another range starts printing.

However, it appears as though the numbers are interleaving when introducing the Thread/sleep into the go-block that reads from the channel. I was under the impression that items are retrieved from a channel in the same order they are put onto the channel?

Is there something I'm missing?


Solution

  • onto-chan executes asynchronously. Each execution of your first go-loop basically starts a new process, putting values onto the channel in parallel. Note the documentation, which states Returns a channel which will close after the items are copied.

    If you wait for onto-chan to finish, you get the expected result:

    (def ch (async/chan 1))
    
    (async/go-loop []
      (Thread/sleep 1000)
      (async/<! (async/onto-chan ch [1 2 3 4 5] false))
      (recur))
    
    (async/go-loop []
      (Thread/sleep 500)
      (when-let [val (async/<! ch)]
        (println val)
        (recur)))