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

8
假设我有一组计算,想要使用core.async异步运行。然而,其中几个函数依赖于其它函数的输出结果。在保证代码清晰的同时也要获得最佳性能,应该如何构建它?
我找到了几个可能的解决方案。
  • 棱形图 - 看起来很合理,但我没有使用core.async通道进行测试;它需要使用fnk,这对我来说有点让人望而却步,因为它需要购买他们的函数定义DSL,但如果这是最好的解决方案,我不介意。
  • Javelin单元 - 仅适用于ClojureScript(目前),并使用FRP而不是CSP作为实现,但它通过公式单元格非常好地建模计算之间的依赖关系。
  • Onyx - 专为分布式计算制作(作为Apache Storm等的竞争对手),但具有处理计算之间依赖关系的“工作流”抽象,并与core.async一起使用。这似乎是最符合我的问题域的解决方案,但我不确定是否需要所有集群管理功能的开销。

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

编辑:添加了Onyx


1
一个promise可以吗? - Dave Yarwood
3个回答

3
这个问题很难回答,因为你的问题缺乏关于使用情况的具体细节。像Graph、Javelin和Onyx这样的库都有不同的用例,不仅仅是使计算互相依赖。
如果您只想让一个线程或go块依赖于系统中其他部分生成的结果,我建议只使用core.async基元,而不需要任何额外的库。
使执行等待另一个活动线程的最基本解决方案是在从通道获取值时使用阻塞接收。当该通道上没有可用值时,这将停止线程(或go块)。
如下面的示例所示,使计算依赖于在另一个线程中完成的活动非常容易。
(let [c (chan)]
  (thread (>!! c “hello”))
  (assert (= “hello” (<!! c)))
  (close! c)

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

是否有任何特定的问题无法使用内置函数清晰地表达?


也许应该这样? (let [c (chan)] (go (>!! c "你好")) (assert (= "你好" (<!! c))) (close! c)) - ctpenrose

1
对于上述第3点,onyx-local-rt可能是适合的选择:
onyx-local-rt是Onyx的替代运行时,可以在纯净、确定性环境中执行作业。此运行时仅限本地使用,不支持分布式模式。这是一个孵化存储库,意味着该代码将在以后的某个日期移入Onyx核心。

1
我认为没有一个权威的解决方法,core.async 是如此新颖,以至于很少有人尝试过。如果我在你的三个选项中选择,我会选择 Graph,它已经在生产环境中部署和测试了一段时间,而且你不需要 Clojurescript 来运行它。如果你对 FRP 解决方案感兴趣,请查看 Java Reactive Extensions,它的 Clojure 绑定存在于 RxClojure 中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接