core-async

Nim Sadeh 2024-05-02T13:46:56.857759Z

Is there a way to send a signal between go-blocks or threads? I know the typical communication piece is a channel, but for what I am thinking I am not sure that can work. Suppose you have the following go block:

(go
  (loop [next-item (
If I use a separate queue to signal the end of the processing loop, I'll have to park waiting for a signal on each loop, which is not what I want (there may be only one signal). I can't end the channel, because it may have an arbitrary number of consumers, not all of whom should be ending. I can use an atom, but I am looking to see if there's a way to do it without holding state

2024-05-02T13:49:26.333309Z

If I understand correctly, This is what a/alt! is for

(go
  (loop []
    (a/alt!
      c ([next-item] (process next-item) (recur))
      signal-tripped-ch :end)))

Nim Sadeh 2024-05-02T13:51:32.261289Z

Ohh I think I completely misunderstood how alt! works until now

2024-05-02T13:54:34.291859Z

It's the coolest/most powerful thing in core.async :)

Nim Sadeh 2024-05-02T13:54:49.706789Z

Thank you, TIL!

Ben Sless 2024-05-02T14:58:06.598359Z

You can also just close the upstream channel

Ben Sless 2024-05-02T15:00:36.319079Z

A nil from the upstream channel signals it is closed

Nim Sadeh 2024-05-02T15:06:42.592209Z

> I can't end the channel, because it may have an arbitrary number of consumers, not all of whom should be ending

Ben Sless 2024-05-02T15:11:49.690919Z

Don't mean to make more work for you, but multiple consumers and multiple producers are an anti pattern, you should use merge and tap

Nim Sadeh 2024-05-02T15:14:15.940259Z

Can you expand on that? I usually use mult. For example, I commonly work with streams from LLM outputs represented as channels. I typically use mult to split the channel in 2, one going to the client over SSE, and the other going to a reducer that posts the reduced output to a database.

Nim Sadeh 2024-05-02T15:15:44.447839Z

For the use case for which I asked about tap, I have a channel of data coming in from the client over websockets. Outputs from an ML streaming algorithm trigger certain async processes to either happen or stop, but I don't want to stop the data coming in from the socket, which has a lot of listeners on it

2024-05-02T17:01:44.990769Z

hard disagree about multiple consumers and producers being an antipattern, merge is convenient in many cases, but merge runs a normal go loop doing a copy and the behavior of doing multiple takes via alts your self vs. the indirection of merge doing it and presenting results over a channel are different.

Ben Sless 2024-05-03T14:50:13.940019Z

It's a very opinionated anti pattern (and I was Wong about tap there) but I find multiple processes producing to multiple channels which are merged cleaner than multiple producers to same channel, buys you the overhead of clean shutdown

2024-05-02T20:43:26.681139Z

@alexmiller I just noticed https://clojure.atlassian.net/browse/ASYNC-209 is closed because I had some code that on review was calling >! outside of a go block, and I knew there was an issue that would have turned that into a compile time error(macro expand time) instead of a runtime error. Having just tripped over this issue, it is a real bummer to see the ticket is both closed as a wontfix and has 0 commentary about why.

Alex Miller (Clojure team) 2024-05-02T20:59:41.084899Z

I can reopen it, don't remember why

2024-05-02T21:03:16.652579Z

I can imagine it not being as simple suggested in the ticket, switch from functions to macros might cause problems with the way the go macro transformation happens, or maybe the risk of breaking the build of exist projects was too high