At this stage, you might be wondering when you should choose one approach over the other. After all, as demonstrated at the beginning of this chapter, we could use core.async to do everything we have done using respondent.
It all comes down to using the right level of abstraction for the task at hand.
core.async gives us many low-level primitives that are extremely useful when working with processes, which need to talk to each other. The core.async channels work as concurrent blocking queues and are an excellent synchronization mechanism in these scenarios.
However, it makes other solutions harder to implement: for instance, channels are single-take by default, so if we have multiple consumers interested in the values that have been put inside a channel, we have to implement the distribution ourselves using tools such as mult and tap.
CES frameworks, on the...