当我编写更多 core.async 代码时,出现的一种非常常见的模式是循环,它在一系列通道上进行切换并执行一些工作来响应消息,例如:
(go-loop [state {}]
(let [[value task] (alts! tasks)]
...work...
(recur state))
不过,我觉得我不理解我实际上可以完成这项工作的各种方式的权衡,所以我想我应该尝试在这里探索它们。
- 内联或通过调用函数:这会阻止循环继续,直到工作完成。由于它位于 go 块中,因此不想执行 I/O 或锁定操作。
- >!发送给工作人员监控的通道的消息:如果通道已满,则会通过停车来阻塞循环,直到通道有容量为止。这允许线程做其他工作并允许背压。
- >!!一条消息:如果通道已满,则会通过休眠运行 go 循环的线程来阻塞。这可能是不可取的,因为 go 线程是严格有限的资源。
- >!另一个 go 块中的消息:这几乎会立即成功,除非没有可用的 go 线程。相反,如果通道已满并且消耗缓慢,则可能会在短时间内导致系统的 go 线程匮乏。
- >!!带有线程块的消息:与 go 块类似,但消耗系统线程而不是 go 线程,因此上限可能更高
- 投入!一条消息:尚不清楚权衡是什么
- 在 future 中调用工作函数:将工作交给 clojure 代理池中的线程来完成,允许 go 循环继续。如果输入速率超过输出速率,则会无限制地增加代理池队列。
这个总结是否正确、全面?
如果要完成的工作完全受 CPU 限制,那么我可能会在go
块,除非它是一个可能需要很长时间的操作并且我想要go
阻止继续响应其他消息。
一般来说,任何不阻塞、睡眠或执行 I/O 的工作都可以安全地放入go
块而不会对系统的吞吐量产生重大影响。
您可以使用>!
将工作提交给一个或一组工人。我几乎永远不会使用>!!
in a go
阻塞,因为它可以阻塞分配给运行的有限数量的线程之一go
blocks.
当您需要执行 I/O 或可能需要长时间运行的计算时,请使用thread
代替go
。这非常类似于future
- 它创建一个真正的线程 - 但它返回一个通道,例如go
.
put!
是一个较低级别的操作,通常在 core.async 的“边界”使用,将其连接到传统的基于回调的接口。很少有任何理由使用put!
里面一个go
.
core.async 可以支持对线程创建方式的细粒度控制。我在博客文章中演示了一些可能性,使用 core.async 进行并行处理 http://stuartsierra.com/2013/12/08/parallel-processing-with-core-async.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)