Concurrency core.async循环在等待从通道读取时被阻止

Concurrency core.async循环在等待从通道读取时被阻止,concurrency,clojure,channel,core.async,Concurrency,Clojure,Channel,Core.async,假设我有一个频道out(chan)。我需要获取放入通道的值并添加它们。值的数量是不确定的(因此不能使用带有()的结束情况的传统循环,并且来自外部IO。我使用带有alts!的固定超时,但这似乎不是解决问题的最佳方法。到目前为止,我得到了以下结果(我从中获得) 我遇到的问题是,超时1000有时是不够的,会导致go循环过早退出(因为IO操作可能需要超过1000毫秒才能完成并将val放入out通道)。我认为增加超时值不是一个好主意,因为它可能会导致我等待的时间过长 保证从out通道进行所有读取并从循环中

假设我有一个频道
out(chan)
。我需要获取放入通道的值并添加它们。值的数量是不确定的(因此不能使用带有
()的结束情况的传统循环,并且来自外部IO。我使用带有
alts!
的固定
超时
,但这似乎不是解决问题的最佳方法。到目前为止,我得到了以下结果(我从中获得)

我遇到的问题是,超时1000有时是不够的,会导致go循环过早退出(因为IO操作可能需要超过1000毫秒才能完成并将val放入
out
通道)。我认为增加超时值不是一个好主意,因为它可能会导致我等待的时间过长

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

更新:

我为什么使用超时? 因为放入通道中的值的数量是不固定的;这意味着,我无法创建退出案例。没有退出案例,go循环将不停地等待(
())将值放入通道输出。如果您有一个没有超时的解算,那将非常棒

我如何知道已读取最后一个值? 我不知道。这就是问题所在。这就是为什么我使用超时和alts!!退出go循环

根据结果,您想做什么? 现在只需要简单的添加。但是,这不是最重要的一点

最终更新:

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

(go-loop
     [[v _] (alts! [out (timeout 1000)])
      i 0
      acc 0]
      (if (and v (not= n i))
        (do
          (>! task-ch (as/progress-tick))
          (recur (alts! [out (timeout 1000)]) (inc i) (+ acc v)))
        (do (close! out)
            (deliver p* (if (= n i) acc nil)))))

我认为您的问题在您的设计中更高一点,而不是特定于核心异步的问题:

一方面,在一个通道中有一个未确定数量的值-可能有0个,可能有10个,可能有1000000个

另一方面,你想阅读所有的内容,做一些计算,然后返回。这是不可能做到的——除非有其他信号,你可以用它来表示“我想我现在完成了”

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


更新:您是否有权访问“上游”IO?您能否在IO操作完成时将sentinel值(如
::closed
)放入通道?

我认为您的问题在您的设计中更高一点,而不是特定于核心异步的问题:

一方面,在一个通道中有一个未确定数量的值-可能有0个,可能有10个,可能有1000000个

另一方面,你想阅读所有的内容,做一些计算,然后返回。这是不可能做到的——除非有其他信号,你可以用它来表示“我想我现在完成了”

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


更新:您有权访问“上游”IO吗?当IO操作完成时,您是否可以向通道输入一个哨兵值(例如
::closed
)呢?

最好的方法是等待来自out的特殊批处理结束消息,或者等待发送方关闭out,以标记输入的结束


无论采用哪种方式,解决方案都取决于发送方传达有关输入的信息。

最好的方式是等待来自out的特殊批处理结束消息,或者等待发送方关闭out以标记输入的结束


无论哪种方式,解决方案都取决于发送方传达有关输入的信息。

a.为什么您甚至需要超时?b.如何知道您是否读取了最后一个值?c.您希望对结果做什么?
alts!!
接收通道向量并从第一次成功的通道操作读取值。如果de>out
通道在超时之前接收到值,我可以继续循环。如果我得到超时通道,这意味着我可以退出循环。我还没有找到退出循环的其他方法,因此我提出了我的问题。我们缺少一条重要信息。如果你不知道有多少值进入,你如何确定现在,当您完成时?这正是我要问的。我不知道有多少值进入。这就是为什么我不能使用退出案例来确定何时完成并使用alts!超时退出读卡器循环。如果是n个值,我可以使用
(dotimes[v(并使用
i
来确定我已经到达终点。我会不顾一切地说,你的做法根本不正确。你不能对无限流求和。任何时候需要使用超时,都有95%的时间表示体系结构中存在错误。基于时间的退出是出了名的不可靠,通常是不可靠的一个对一个糟糕的设计选择的带帮助。为什么你甚至需要超时?B。你怎么知道你读过最后一个值?C。你想对结果做些什么?<代码> ALTS!< /Cord>取一个通道的向量并从第一个成功的通道操作中读取值。如果<代码> OUT/<代码>通道在超时之前接收值。,我可以继续循环。如果我得到超时通道,这意味着我可以退出循环。我还没有找到退出循环的其他方法,因此我提出了我的问题。我们缺少一条重要信息。如果你不知道有多少值进入,你如何知道何时完成?这正是我要问的。我不知道我不知道有多少值进入。这就是为什么我不能使用退出案例来确定何时完成,并已求助于使用alts!to
(go-loop
     [[v _] (alts! [out (timeout 1000)])
      i 0
      acc 0]
      (if (and v (not= n i))
        (do
          (>! task-ch (as/progress-tick))
          (recur (alts! [out (timeout 1000)]) (inc i) (+ acc v)))
        (do (close! out)
            (deliver p* (if (= n i) acc nil)))))