如何清楚地构建 core.async 个通道之间的依赖关系?

How does one clearly structure dependencies between core.async channels?

假设我有一个计算语料库,我想使用 core.async 异步 运行,但不幸的是,一些函数依赖于 other[= 的输出29=] 函数。如何在我的代码中清晰地构建它,同时获得最佳性能?

我遇到的一些潜在解决方案是

  • Prismatic's Graph - 似乎是合理的,虽然我没有用 core.async 频道测试它;它需要使用 fnk 的事实对我来说有点令人反感,因为它需要购买他们的 DSL 来定义函数,但如果这是最好的解决方案,那么我不介意。
  • Javelin cells - 仅适用于 ClojureScript(当前)并使用 FRP 而不是 CSP 作为实现,但它在通过公式单元对计算之间的依赖关系进行建模方面做得非常好。
  • Onyx - 用于分布式计算(作为 Apache Storm 等的竞争对手)但具有 "workflow" 抽象来处理计算之间的依赖关系并与 core.async 一起工作。这似乎最适合我的问题领域,但我不确定我是否需要所有集群管理功能的开销。

这个问题的规范解是什么?

编辑:添加了 Onyx

我不认为有解决它的规范方法,core.async 太新了,很少有人尝试过。如果我要在你的三个选项中做出选择,我会选择 Graph,它已经在生产中部署和测试了一段时间,你不需要 Clojurescript 来 运行 它。如果您对 FRP 解决方案感兴趣,请查看 Java Reactive Extensions, Clojure bindings for it exist in RxClojure

这个问题有点难以回答,因为你的问题缺乏关于你的用例的细节。像 Graph、Javelin 和 Onyx 这样的库都有不同的用例,不仅仅是使计算相互依赖。

如果您只想让线程或 go 块依赖于系统另一部分生成的结果,我建议您只使用 core.async 基元而不使用任何其他库。

让执行等待 activity 的另一个线程的最基本解决方案是在从通道获取值时使用阻塞获取。当该通道上没有可用值时,这将停止线程(或进入块)。

如您在以下示例中所见,根据在另一个线程中完成的 activity 进行计算非常容易。

(let [c (chan)]
  (thread (>!! c “hello”))
  (assert (= “hello” (<!! c)))
  (close! c)

还有更精细的机制可用。 Alts!! 函数提供了同时等待多个通道的能力。 pipeline 函数的几种不同风格允许您以类似数据流的方式对并发进行建模。

您是否遇到过运行无法使用内置函数清楚表达的具体问题?

对于上面的 #3,onyx-local-rt 可能符合要求:

onyx-local-rt is an alternative runtime for Onyx that executes jobs in a pure, deterministic environment. This runtime is local-only, and does not run in a distributed mode. This is an incubating repository, meaning this code will be moved into Onyx core at a later date.