Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I did use agents in the past, but stopped since core.async became available: it addresses the use cases for agents in a much more flexible way. Also, I found that handling errors in agents is difficult.

As for the general use case, atoms and core.async are great tools, and I haven't needed to use refs (aka the STM) for years.




Don't the core.async go-blocks have issues if you need to block on IO heavy stuff, as in the thread-pool will be blocked until the side-effects are done? Agents don't have that problem, at least I don't think they do.


Yeah this is true, typically you want to keep blocking functions outside this. By default, core.async allocates as many threads as cores in your CPU.

In addition to this, I personally find core.async to deal poorly with flow control (e.g. slow subscribers slowing down the entire flow for every subscriber), and seems to not have a lot of telemetry / it’s difficult to find out what’s going on in the thread pool behind it.

I’ve personally settled on Zach Tellman’s Manifold library, which provides a much more sane abstraction and is fully compatible with core.async.

For some addition thought and material on these topics, I highly recommend watching this talk by Zach, “Everything Will Flow” https://youtu.be/1bNOO3xxMc0


Hmm, interesting — but manifold is clj-only, and I use core.async both on server side and client-side in ClojureScript.


Well, they don't have "issues", they are simply not intended for I/O — but you can simply do your I/O processing in a (thread) block instead of a (go) block and use <!! instead of <!. The beauty of core.async channels is that one end of a channel can be used in a go block and another end in a thread block, and things will be fine. I use this a lot in practice.

Agents also have a fixed thread pool, and you should use send-off if you intend to do I/O.


All of the core.async operations having blocking versions (eg. >!! vs. >!) which means you can use your own threads/thread pools for any work, if needed. Basically, you create your own threads instead of using go blocks and then use the blocking operations, >!!, <!!, alts!!, alt!!, etc.


I believe all I/O is blocking unless you use something that wraps NIO. This is definitely true for core.async threads, but I'm not sure why it would any different for agents.

This is also a bit of a departure for people coming from Go or Erlang/Elixir.


Agents are run in a separate pool, and no one agent is processing at a time, so I suppose they're not "parallel", but concurrent still. I think the agents are preemptive, but I'm not 100% sure on that.


I found this comment enlightening: https://clojuredocs.org/clojure.core/send-off#example-593472...

It seems like there are a lot of parallels between agents and core.async.

Agents, like go blocks, run in a thread pool. Any blocking IO should be pushed off to a separate thread outside of the thread pool. In the case of agents, there is (send-off). In the case of core.async, there is (thread)




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: