在clojure core.async go-loop中进行工作的方法有什么权衡?

时间:2014-07-23 15:42:38

标签: clojure core.async

当我编写更多core.async代码时,出现的一个非常常见的模式是一个循环,它会在一系列通道上发生变化,并且会响应一条消息而起作用,例如:

(go-loop [state {}]
  (let [[value task] (alts! tasks)]
    ...work...
    (recur state))

我不觉得我理解实际工作的各种方式的权衡,所以我想我会尝试在这里探索它们。

  • 内联或通过调用函数:这会阻止循环继续直到工作完成。由于它是一个go块,人们不想做I / O或锁定操作。
  • &GT ;!向工作人员监控的频道发送的消息:如果频道已满,则会通过停车来阻止循环直到频道具有容量。这允许线程做其他工作并允许背压。
  • >!消息:如果通道已满,则通过休眠运行go循环的线程来阻止。这可能是不合需要的,因为go thread是一个严格有限的资源。
  • &GT ;!另一个go块中的消息:除非没有可用的线程,否则这几乎会立即成功。相反,如果频道已满并且正在慢慢消耗,这可能会在短时间内使线程系统挨饿。
  • >!带有线程块​​的消息:类似于go块,但是消耗系统线程而不是去线程,所以上限可能更高
  • 放!消息:它不清楚是什么权衡
  • 将来调用工作函数:将工作交给clojure代理池中的一个线程来做,允许go循环继续。如果输入速率超过输出速率,则会使代理池队列不受限制地增长。

此摘要是否正确且全面?

1 个答案:

答案 0 :(得分:5)

如果要完成的工作完全受CPU限制,那么我可能会在go块中内联,除非它的操作可能需要很长时间,我想要{ {1}}阻止继续回复其他消息。

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

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

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

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

core.async可以支持对线程创建方式的细粒度控制。我在博客文章Parallel Processing with core.async中展示了一些可能性。