Skip to content
Josh edited this page Apr 2, 2022 · 2 revisions

Core.async Conceptual Overview

Core.async is built around the concept of channels. One part of the program, an "endpoint", puts messages onto a channel, and then continues executing other code. Another endpoint receives messages from the channel asynchronously, on some other thread; the caller is not aware of what happens to the message after it is sent, and does not have to wait around for the recipient to accept the message.

In this way, loose coupling between various programming components is achieved and callback hell is avoided. Channels can be disconnected from one endpoint and connected to another. Endpoints can be altered without altering other systems. Channels can connect endpoints directly, or arbitrarily complex routing infrastructure can be built up between endpoints.

The most basic example: Hello, world!

Let's walk through the most basic core.async example possible, "Hello, world!". We will create a channel and write a message to it, then retrieve it.

user> (require '[clojure.core.async :as async])
nil
user> (def a-channel (async/chan 1))
#<Var@322a141: 
   #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@29a7b991>>
user> (async/>!! a-channel "Hello, world!")
true
user> (async/<!! a-channel)
"Hello, world!"

After requiring the clojure.core.async namespace, we create a channel by calling (chan 1). The number 1 defines the size of the buffer that the channel should have; it will have the capacity to store 1 message. (If we had omitted the 1, the channel would have no internal buffer at all by default, which means that it would block the sending thread until a receiver became available. Since we are only working with one REPL thread in this example, this is obviously undesirable.)

With our channel defined, we call (>!!) to write a message to it. (There are other ways of putting a message onto a channel, but this is the most basic.) >!! blocks the sending thread until the channel accepts the message, which is not a problem in this case since this channel has free buffer space. If we try to send a second message before the first is delivered, >!! will block! As it is, though, the channel immediately accepts the message and returns true, indicating that the channel is not closed and has accepted the message.

We then call (<!!) on the same channel to dequeue the message we just sent, and indeed, it immediately returns "Hello, world!". In a real scenario, this would probably happen in another thread, which would take some action based on the message contents.

Many more complicated scenarios are possible.