alts 的最佳方法是什么!!在通道向量上多次?

what's the best way to alts!! on a vector of channel multiple times?

我正在使用 core.async 并行执行某些操作,然后使用 alts!! 等待一定数量的结果并超时。

(ns c
  (:require [clojure.core.async :as a]))

(defn async-call-on-vector [v]
  (mapv (fn [n]
          (a/go (a/<! (a/timeout n)) ; simulate long time work
                n))
        v))

(defn wait-result-with-timeout [chans num-to-get timeout]
  (let [chans-count (count chans)
        num-to-get (min num-to-get
                        chans-count)]
    (if (empty? chans)
      []
      (let [timeout (a/timeout timeout)]
        (loop [result []
               met 0]
          (if (or (= (count result) num-to-get)
                  (= met chans-count)) ; all chan has been consumed
            result
            (let [[v c] (a/alts!! (conj chans timeout))]
              (if (= c timeout)
                result
                (case v
                  nil (do (println "got nil") (recur result met)) ; close! on that channel
                  (recur (conj result v) (inc met)))))))))))

然后像这样调用:

user=> (-> [1 200 300 400 500] c/async-call-on-vector (c/wait-result-with-timeout 2 30))

这个表达式会打印出很多got nil。似乎 go 块 returned 的通道将在结果被 returned 后关闭该通道。在这种情况下,这将导致 alts!! return nil。但这很CPU不友好,就像忙着等待一样。有没有办法避免这种情况?

我通过定义像 go 这样的宏来解决这个问题,但是 return 一个不会在结果 returned 时关闭的通道。这是解决问题的正确方法吗?

I'm using core.async to do something in parallel, and then using alts!! wait on certain amount of result with timeout.

您似乎想要收集将由某些通道传送的所有值,直到所有这些通道都关闭,或者直到发生超时。一种方法是将这些通道 merge 放到一个通道上,然后在 go-loop 中使用 alts! 将值收集到向量中:

(defn wait-result-with-timeout [chans timeout]
  (let [all-chans (a/merge chans)
        t-out (a/timeout timeout)]
    (a/go-loop [vs []]
      (let [[v _] (a/alts! [all-chans t-out])]
        ;; v will be nil if either every channel in
        ;; `chans` is closed, or if `t-out` fires.
        (if (nil? v)
          vs
          (recur (conj vs v)))))))

It seems channel returned by go block will close that channel after result has been returned.

你是对的,这是一个 go 块的记录行为。

I solved this by define a macro like go, but return a channel that will not closed on result returned. Is this a right way to solve it?

可能不会,尽管我不能说它对您的特定用例是对还是错。一般而言,通道在传递完价值后应该关闭,以表明完成传递价值的语义。例如,上面的代码使用 all-chans 的结束来表示没有更多的工作要等待。