user508458
user508458

Reputation:

What are the tradeoffs of the ways to do work in a clojure core.async go-loop?

As I write more core.async code, a very common pattern that emerges is a go-loop that alts over a sequence of channels and does some work in response to a message, e.g.:

(go-loop [state {}]
  (let [[value task] (alts! tasks)]
    ...work...
    (recur state))

I don't feel like I understand the tradeoffs of the various ways I can actually do the work though, so I thought I'd try to explore them here.

Is this summary correct and comprehensive?

Upvotes: 4

Views: 1149

Answers (1)

Alessandra Sierra
Alessandra Sierra

Reputation: 10897

If the work to be done is entirely CPU-bound, then I would probably do it inline in the go block, unless it's an operation that may take a long time and I want the go block to continue responding to other messages.

In general, any work which doesn't block, sleep, or do I/O can be safely put in a go block without having a major impact on the throughput of the system.

You can use >! to submit work to a worker or pool of workers. I would almost never use >!! in a go block because it can block one of the finite number of threads allocated to running go blocks.

When you need to do I/O or a potentially long-running computation, use a thread instead of a go. This is very similar to future — it creates a real thread — but it returns a channel like go.

put! is a lower-level operation generally used at the "boundaries" of core.async to connect it to conventional callback-based interfaces. There's rarely any reason to use put! inside a go.

core.async can support fine-grained control over how threads are created. I demonstrated a few possibilities in a blog post, Parallel Processing with core.async.

Upvotes: 4

Related Questions