在clojure core.async go循环中,工作方式的权衡是什么?

在clojure core.async go循环中,工作方式的权衡是什么?,clojure,core.async,Clojure,Core.async,随着我编写更多的core.async代码,出现了一种非常常见的模式,即go循环,它在一系列通道上交替,并对消息进行响应,例如: (go-loop [state {}] (let [[value task] (alts! tasks)] ...work... (recur state)) 我觉得我不明白我可以用各种方法来完成这项工作,所以我想在这里尝试探索一下 内联或通过调用函数:这会阻止循环继续,直到工作完成。因为它位于go块中,所以不希望执行I/O或锁定操作 >!!一条

随着我编写更多的core.async代码,出现了一种非常常见的模式,即go循环,它在一系列通道上交替,并对消息进行响应,例如:

(go-loop [state {}]
  (let [[value task] (alts! tasks)]
    ...work...
    (recur state))
我觉得我不明白我可以用各种方法来完成这项工作,所以我想在这里尝试探索一下

  • 内联或通过调用函数:这会阻止循环继续,直到工作完成。因为它位于go块中,所以不希望执行I/O或锁定操作
  • >!!一条消息发送到一个由工作者监控的通道:如果通道已满,这将通过停车阻止环路,直到通道有容量为止。这允许螺纹进行其他工作,并允许背压
  • >!!一条消息:如果通道已满,将通过休眠运行go循环的线程来阻塞。这可能是不可取的,因为go线程是一种严格有限的资源
  • >!!另一个go块中的消息:除非没有可用的go线程,否则这将几乎立即成功。相反,如果通道已满且消耗缓慢,则可能会在短时间内耗尽系统中的go线程
  • >!!带有线程块的消息:与go块类似,但使用系统线程而不是go线程,因此上限可能更高
  • 放!一条信息:不清楚权衡是什么
  • 将来调用work函数:将工作从clojure代理池中分配给线程执行,允许go循环继续。如果输入速率超过输出速率,则会无限制地增长代理池队列

此摘要正确且全面吗?

如果要完成的工作完全受CPU限制,则我可能会在
go
块中内联完成,除非这是一个可能需要很长时间的操作,并且我希望
go
块继续响应其他消息

通常,任何不阻塞、睡眠或执行I/O的工作都可以安全地放入
go
块中,而不会对系统的吞吐量产生重大影响

您可以使用
>将工作提交给工作人员或工作人员池。我几乎不会使用
>
go
块中,因为它可以阻止分配给运行
go
块的有限数量的线程之一

当您需要执行I/O或可能长时间运行的计算时,请使用
线程
而不是
go
。这非常类似于
future
——它创建了一个真正的线程——但它返回一个类似
go
的通道

put
是一个较低级别的操作,通常用于core.async的“边界”,将其连接到传统的基于回调的接口。很少有理由使用
put
go

async可以支持对线程创建方式的细粒度控制。我在一篇博文中展示了一些可能性