core.async循环阻止等待从频道

时间:2018-02-15 16:11:57

标签: concurrency clojure channel core.async

假设我有一个频道out (chan)。我需要获取放入通道的值并添加它们。值的数量未确定(因此不能使用带有(<! out)的结束情况的传统循环)并且来自外部IO。我使用固定的timeoutalts!,但这似乎不是解决问题的最佳方法。到目前为止,我已经得到了以下内容(我从https://gist.github.com/schaueho/5726a96641693dce3e47获得)

(go-loop
      [[v ch] (alts! [out (timeout 1000)])
       acc 0]
      (if-not v
        (do (close! out)
            (deliver p acc))
        (do
          (>! task-ch (as/progress-tick))
          (recur (alts! [out (timeout 1000)]) (+ acc v)))))

我遇到的问题是1000的超时有时是不够的,导致go-loop过早退出(因为完成IO操作可能需要1000多秒才能完成并将val放入{{ 1}}频道)。我不认为增加超时值是一个好主意,因为它可能会让我等待超过必要的时间。

保证所有来自out通道的读取并从循环中正确退出的最佳方法是什么?

更新

为什么我使用超时? 因为放入通道的值的数量不固定;这意味着,我无法创建退出案例。如果没有退出情况,那么go-loop将默认等待(out)等待放入通道中的值。如果你有一个没有超时的解决方案,那真的很棒。

我怎么知道我读过最后一个值? 我不。那就是问题所在。这就是我使用超时和等待的原因!退出循环。

你想做什么结果? 现在简单补充一下。但是,这不是重要的一点。

更新最终结果:

我找到了一种方法来获取我要处理的值的数量。所以我修改了我的逻辑以利用它。我还是要使用超时和alts!防止任何锁定。

(<! out)

2 个答案:

答案 0 :(得分:2)

我认为你的设计中的问题有点高,而不是特定于核心的异步:

一方面,你有一个未确定的数值来自一个频道 - 可能有0,可能有10,可能有1,000,000。

另一方面,您想要阅读所有,进行一些计算然后返回。这是不可能的 - 除非有其他信号可以用来说“我想我现在已经完成了”。

如果该信号是值的时间,那么使用alts!的方法是正确的,尽管我相信代码可以简化一点。

更新:您是否可以访问“上游”IO?当IO操作完成时,你可以将一个标记值(例如::closed)放到通道中吗?

答案 1 :(得分:2)

最好的&#39;方法是等待来自out的特殊批量结束消息或由发送者关闭以标记输入的结束。

无论哪种方式,解决方案都由发件人传达有关输入的信息。