Fork me on GitHub
#core-async
<
2017-01-25
>
bcbradley01:01:31

if you have a bunch of go block code executing concurrently, is it possible for one of them to be starved?

bcbradley01:01:47

does core.async make any promises about starvation?

tbaldridge02:01:34

But back pressure makes starvation a rather rare occurrence

stuartrexking09:01:14

Does core.async have a range over channels form like golang has?

stuartrexking09:01:25

go-loop might work.

rauh10:01:16

@stuartrexking The doall ..... map is actually your problem why it hangs

rauh10:01:49

The go macro won't walk into the anonymous function (here #(>! out %)) and rewrite the >! "function call".

rauh10:01:06

Use

(doseq [n nums]
        (>! out n))

stuartrexking10:01:52

I’ll give that a go.

stuartrexking10:01:56

Works great, thanks.

stuartrexking10:01:29

So don’t use anonymous functions in go blocks?

rauh10:01:46

You can, but just don't use <! nor >! in anonymous functions

rauh10:01:59

the macro won't walk into that (fn) form

stuartrexking10:01:04

Ah. Great. Thanks.

joshjones14:01:13

@stuartrexking Wanted to say thanks for linking to the golang example. In case you’re interested, after using the more primitive way of squaring the ints in the example, here’s a way to do it using a more rich set of tools from the core.async library, namely to-chan and map:

(defn square-ints-v2
  [start end]
  (let [ints (a/to-chan (range start (inc end)))
        squares (a/map #(* % %) [ints])]
    (go-loop []
      (when-let [i (<! squares)]
        (println i)
        (recur)))))

(square-ints-v2 30 40)

joshjones16:01:49

another way, using a transducer and a bit more collection-oriented — btw, core.async gurus, please give me some feedback on whether this type of construct would be typical or not

(defn square-ints-v2
  [start end]
  (let [square-chan (chan 1 (map #(* % %)))]
    (a/onto-chan square-chan (range start (inc end)))
    (a/<!! (a/into [] square-chan))))

(run! println (square-ints-v2 30 40))

stuartrexking00:01:59

joshjones: Thanks!

joshjones00:01:17

:thumbsup::skin-tone-2:

jgdavey16:01:46

@joshjones async/map and friends are deprecated, and I definitely see your most recent example as the preferred.

jgdavey16:01:22

So, yes, that type of construct (transducer on channel) is typical 🙂

joshjones16:01:08

thanks @jgdavey , according to the docs, only the map< and map> are actually deprecated (not map itself)?

jgdavey16:01:38

Ah, yes, I think you’re right.

joshjones16:01:15

i know though that transducers were in part implemented due to having to rewrite mapcat<, map<, etc. again for core.async — but it seems that map itself is a bit of a different animal

jgdavey16:01:36

But typically I’d see a transducer when you’re mapping values across a channel. I think map is used when you need to do something with multiple channels

joshjones16:01:13

that makes sense — the fact that it takes multiple channels is a bit strange, and I will prefer a transducers-based approach — your feedback is welcome, thanks 🙂

tbaldridge17:01:29

@joshjones yes, I lobbied for Rich to add map because there are cases where you want one value from each channel to be combined, and that can be solved like this: (async/map vector a b) and what you get out is [a1 b1] [a2 b2] [a3 b3]