【问题标题】:Clojure - Why does execution hang when doing blocking insert into channel? (core.async)Clojure - 为什么在阻塞插入通道时执行挂起? (core.async)
【发布时间】:2014-01-22 12:51:16
【问题描述】:

考虑以下 sn-p:

(let [chs (repeatedly 10 chan)]
  (doseq [c chs]
    (>!! c "hello"))
  (doseq [c chs]
    (println (<!! c))))

执行此操作将永远挂起。这是为什么呢?

如果我改为使用(go (&gt;! c "hello")),它就可以正常工作。

【问题讨论】:

    标签: clojure core.async


    【解决方案1】:

    要进行异步放置,请使用clojure.core.async/put!

    (let [chs (repeatedly 10 chan)]
      (doseq [c chs]
        (put! c "hello"))
      (doseq [c chs]
        (println (<!! c))))
    

    这在本例中有效,因为 &lt;!! 将始终解除阻塞,因为所有必要的 put 都是异步发生的。请注意以下几点:

    • 阻塞用作不同进程之间的同步约束
    • &gt;!!&lt;!! 阻塞主线程。 go 例程在主线程上运行,但它们的代码通过宏扩展进行修改,以便反转执行控制,并且它们可以按照core.async 通道阻塞/缓冲逻辑的规律依次停放/执行。这种技术通常称为 IOC(控制反转)状态机。
    • ClojureScript 只有一个线程。因此,它对core.async 的实现甚至不包含&gt;!!/&lt;!!。如果您编写的代码旨在与 ClojureScript 兼容,则仅从 go-routines 中的通道获取或以传递给 take! 的高阶函数从它们中分派值,并且始终在 go-routines 中放置或使用 put! .

    (go (&gt;! ch v)) 是否等同于 (put! ch v)

    是的,但不一样。 put! 是围绕 core.async.impl.protocols/WritePort put! 方法的通道实现的 API 包装器。 (go (&gt;! ch v)) 的宏扩展最终发生在相同的方法调用中,但将其包装在大量生成的状态机代码中,以可能停止放置操作并暂停 go 例程的执行,直到消费者准备好从 @987654342 获取@(自己尝试(macroexpand `(go (&gt;! ch v))))。生成一个 go-block 只做一个异步 put 操作有点浪费,而且性能比立即调用put! 更差。 go 生成并返回一个额外的通道,您可以从中获取其主体结果。这使您可以等待其执行完成,而您在示例中并不打算这样做(针对异步操作)。

    【讨论】:

    • (put! c) 是否等同于 (go (&gt;! c))
    • 我编辑了我的答案,希望能提供更多见解。
    【解决方案2】:

    该通道没有缓冲区,&gt;!! 正在阻塞。具体情况请参阅the examples。出于这个原因,它们产生了第二个线程 - 以防止阻塞主线程。在您的问题中,使用 goroutine 的操作原理类似。

    您还可以创建带有一些缓冲区空间的通道 - (chan 1)

    【讨论】:

    • 啊,我忘了puts 也在阻塞。他们阻止什么? gets 更直观,因为它们会阻止通道中存在的值。但是当你put某事时,你在阻止什么?
    • 你的问题标题是“阻止插入”,所以你至少下意识地知道。 :-) 基本上,它会阻塞,直到通道能够接收到值。在这种情况下,这意味着有一个消费者准备立即获取价值。我不知道实现细节,但从概念上讲,没有缓冲区的通道只是一个同步点。使用带有缓冲区的通道,它将在阻塞发生之前保存n 个项目。
    • @MarkF puts,你的意思是&gt;!/&gt;!!吗?有一个put! 函数与这些函数执行相同的操作,但不会阻塞调用线程。
    猜你喜欢
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多