2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!有关如何使用本站的信息,请参阅关于 页面。

0
Clojure
重分类

我试图将一个通道转换为序列。这是我目前使用的:

(defn chan->seq [ch]
  (when [v (<!! ch)]
    (lazy-seq (cons v (chan->seq ch)))))

它可以工作,但是它使用的是阻塞读取,因此当前线程将在通道关闭之前被阻塞,并且不能同时激活很多此函数的调用。是否有此函数的非阻塞版本?

此示例展示了该问题

(doseq [_ (range 20)]
  (go (chan->seq (chan 10))))

(go (println :OK))

由于chan->seq调用的请求占满了线程池中的所有线程,因此最后一行不会打印任何内容。如果将20改为5(在新会话中),则可以工作。

1 答案

0

编辑

您的实现是好的。

我们编写并使用了一些非常相似的东西

https://github.com/techascent/tech.parallel/blob/cc1b9b0ef8a0893fe1278a700a4dbb0271f92156/src/tech/parallel.clj#L38-L53

你不能同时激活此函数的1000个调用

我不太确定这一点。你试过了吗?

在资源受限制的某些条件下,已停靠的线程的堆栈使用可能会引起内存压力,但一般来说,现代调度器可以很好地处理大量停靠的线程(如果恢复线程的耗时不是 O(1),那将令我感到惊讶——至少在我们使用的基础上是如此——在AWS上各种EC2机器上运行的Linux上的OpenJDK)。

希望这能帮到您。

数量不一定是1000,20也行。我已经通过一个示例更新了问题。
在那个情况下,`go`就是罪魁祸首。"go"使用自己的线程池,而且线程不多。但是!因为读取是阻塞的,所以您在这里根本不需要使用"go"。请参见我提供的实现,它可以在多线程环境下工作。
如果我想在go块内使用这个函数呢?或者是在没有阻塞操作的clojurescript中?

编辑
在这种情况下,这可能有点复杂。您可能需要了解更多关于问题的东西(比如项目出现的模式/时间/频率),然后利用这些来构建非阻塞的、可能可重启动的、带超时限制的或类似的东西。在许多情况下,JavaScript仍然有效地是单线程的。
...