等待Clojure异步通道的惯用方式是什么?

5
这是当前的代码版本,它执行非常简单的任务。它启动10个go例程,每个例程将10条消息添加到通道中。另一端是一个while true循环,它读取通道并在每500毫秒超时一次。
我在考虑使用更好的方式。我认为while true循环可以替换为一个recur,其中它读取通道,在每次成功读取后返回以再次读取。如果发生超时,它只终止执行。
我有两个问题: - 这是正确的方法吗? - 如何使用惯用的Clojure实现它?
(defn -main [& args]
  (let [c (async/chan)]
    (doseq [i (range 10)]
      (async/go
        (doseq [j (range 10)]
          (Thread/sleep (rand-int 1000))
          (async/>! c (str i " :: " j)))))
    (while  true
    (async/<!!
      (async/go
        (let [[result source] (async/alts! [c (async/timeout 500)])]
          (if (= source c)
            (println "Got a value!" result)
            (println "Timeout!"))))))))

2
我认为在 core.async 代码中使用 Thread/sleep 的任何情况都是一种代码异味 -- 这样做只会无端地占用线程池资源。我想不出任何场景下使用 timeout<!<!! 不是更合适的选择。 - Charles Duffy
...是的,我同意从通道中读取循环/递归将是惯用的做法。 - Charles Duffy
1个回答

7

这是一种非常常见的方法,所以回答你的第一个问题,我会说是的。core.async 提供了一些方便之处,可以使它更加符合惯例(尽管它现在的状态已经很好了):

  • 使用 go-loop 而不是 (go (while true ...))(go (loop ...))
  • 使用 alt! 而不是 (let [[result channel]] (alts! ...))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接