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(在新 repl 会话中),它将工作。

1 答案

0 投票

编辑

您的实现很好。

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

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

不能同时有 1000 次对此函数的调用

我对此并不十分确定。你尝试过了吗?

在某些资源受限的条件下,暂停线程的栈使用可能导致内存压力,但在一般情况下,现代调度器在处理大量暂停线程时表现良好(如果恢复线程不是O(1),我会感到惊讶——至少在我们使用的系统中是这样,即AWS上各种EC2机器上的OpenJDK)。

希望这能帮到您。

不用非得是1000,20也是可以的。我已经在问题中提供了一个示例。
哦,如果是那样的话,'go'就是罪魁祸首。'go'使用自己的线程池,而且线程不多。但是!由于读取是阻塞的,您在这里根本不需要'go'。看我在链接中提供的实现,它可以与许多线程一起工作。
如果我想在go块内使用这个函数怎么办?或者是在clojurescript中,它没有阻塞操作。

编辑了
在这种情况下,可能更复杂一些。你可能需要了解一些关于问题的其他信息(比如在通道上显示的项的图案/时间/频率),并利用这些信息来构建非阻塞的、可能重启并带有超时或者类似的解决方案。在许多情况下,JavaScript 仍然有效地是单线程的。
...