gpt4 book ai didi

Clojure-在将阻塞插入 channel 时为什么执行挂起? (core.async)

转载 作者:行者123 更新时间:2023-12-03 21:47:17 28 4
gpt4 key购买 nike

考虑以下代码段:

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

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

如果我改用 (go (>! c "hello")),则效果很好。

最佳答案

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

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

在此示例中,这是可行的,因为由于所有必需的放置操作都是异步发生的,因此 <!!始终会解除阻止。请注意以下几点:
  • 阻塞充当不同进程之间的同步约束
  • >!!<!!阻塞主线程。 go例程在主线程上运行,但是它们的代码通过宏扩展进行了修改,因此执行控制被反转,并且可以按照core.async channel 阻塞/缓冲逻辑定律依次对其进行停放/执行。此技术通常称为IOC(控制反转)状态机。
  • ClojureScript只有一个线程。因此,它的core.async实现甚至不包含>!!/<!!。如果编写旨在与ClojureScript兼容的代码,则只能从go -routines内的 channel 获取,或以传递给take!的高阶函数从它们中分发值,并且始终将其放入go -routines或使用put!

  • (go (>! ch v))等效于(put! ch v)吗?

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

    关于Clojure-在将阻塞插入 channel 时为什么执行挂起? (core.async),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20927582/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com