Learn the core ideas of CSP, how core.async approximates them in Clojure, and where explicit channel communication beats shared mutable state.
CSP (Communicating Sequential Processes): A concurrency model in which independent processes coordinate by exchanging values through channels rather than sharing mutable state directly.
CSP matters in Clojure because it gives a mental model for core.async that is more useful than “async but with channels.” The key idea is simple:
That is different from building concurrency around many threads reaching into the same mutable structure.
core.async is not a pure academic CSP implementation, but it captures the practical lessons well:
This makes the communication graph visible in the code.
Channels make handoff points concrete:
1(def requests (async/chan 32))
2(def responses (async/chan 32))
Now the design has visible questions:
requests?Those questions are harder to ignore than they are with shared mutable state.
The most valuable CSP lesson is not syntax. It is ownership. Each process should be responsible for:
If many processes are still coordinating through hidden shared state, the code has borrowed channel syntax without adopting the model.
It fits best when:
It fits poorly when:
A useful CSP-style channel answers:
Without those rules, the program may use channels while still leaving the communication contract implicit.
In CSP-style designs, channel closure is not a cleanup detail. It is part of the meaning of the stream. A consumer needs to know whether closure means normal completion, upstream failure, no more work for this partition, or system shutdown.
That is why good channel design documents:
This is a useful contrast:
If several values must change together atomically, refs and transactions are the right story. If the main problem is staged communication between independent actors, channels are often the clearer story.
The most common misuse of CSP style in Clojure is keeping the shared mutable design and merely wrapping it with channels. If every process still depends on global mutable coordination, the model has not really changed.
Use the CSP model to reason about core.async systems in terms of ownership and message flow. If the communication edges are explicit and the state remains local where possible, the design is usually much easier to scale and debug.