Clojure核心异步put!与go块的比较

7
我读过这篇关于核心异步的好文章: http://www.core-async.info/reference/primitives 我理解:
1. put! 是异步的并可以接受回调。在简单场景下运作良好,但可能会陷入回调地狱。 2. go 可以解决回调地狱问题,并允许使用同步方式编写异步代码。 3. go 利用轻量级线程池和停车来实现并发。 4. go 使用有限状态机。
我不明白:
1. put! 如何实现异步?它是否也使用线程池? 2. put! 是否也使用停车? 3. 有限状态机在go块中的作用是什么?它是否实现了停车? 4. 我应该始终尝试使用put!而不是go因为它更便宜吗?这是否意味着put!可以实现与go完全一样的并发性能,只有在需要处理复杂的异步代码时才使用go?
感谢您为我们解开这些谜团。
1个回答

11

如果您想了解core.async通道的工作原理,没有比Rich Hickey在EuroClojure 2014演讲更好的资料:Implementation details of core.async channels

至于您的具体问题:

  1. 如果put!不能立即接受,则会在通道内部的队列上放置一个挂起的put(要放置在通道上的值+ put!回调)。请注意,如果队列中没有空间(最大容量目前固定为1024),将抛出异常。

    如果满足以下条件之一,回调函数将在池化线程上调用:
    (1)put未被立即接受;
    (2)向put!调用传递了明确的false作为最后一个参数(此参数称为on-caller?,有关详细信息,请参见put!的文档字符串)。

  2. go块的上下文中,“Parking”指暂停go块状态机的执行,通过记录其当前状态的某些细节并将它们保存在一个或多个通道中以便稍后重新启动。 (请注意,这种安排意味着,如果所有保持对挂起的go块引用的通道都被GC'd,则go块本身也可以被GC'd。)在其他上下文中,它同样指将控制线程置于暂停状态。 put!只是一个函数(好吧,它由协议方法支持,但是只是一个协议方法),因此此概念不适用。

  3. 是的。它基本上会在go块中的代码中进行步骤,可能在控制到达某些“自定义终端”(<!>!alt!)时暂停。

  4. 不一定,请首先考虑溢出内部队列的风险(请参见上面的第1点)。


太棒了,Michal!我刚刚看完EuroClojure的演讲,真是受益匪浅。感谢你指出这个演讲。 - Nicolas Dao
1
很想看到一些并列使用情况,以了解何时使用各种端口语义 :) - Petrus Theron
这里有幻灯片:http://cdn.cognitect.com/presentations/2014/insidechannels.pdf - Jeremy Field

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