在Clojure中应该使用哪一个?是块还是线程?

时间:2019-03-27 02:23:24

标签: multithreading clojure

我想看看Clojure中线程和长时间运行的go块之间的内在区别。特别是,我想弄清楚应该在上下文中使用哪一个。

我知道如果创建了一个go-block,那么它将被管理在所谓的线程池中运行,默认大小为8。但是thread将创建一个新线程。

在我的情况下,有一个输入流从某处获取值,并将该值作为输入。执行一些计算,并将结果插入结果通道。简而言之,我们有输入和输出通道,并且计算是在循环中完成的。为了实现并发性,我有两种选择,要么使用go块,要么使用thread

我想知道两者之间的内在区别是什么。 (我们可能会假设计算期间没有I / O。)示例代码如下所示:

(go-loop []
  (when-let [input (<! input-stream)]

  ... ; calculations here

  (>! result-chan result))
  (recur))

(thread
  (loop []
    (when-let [input (<!! input-stream)]

    ...  ; calculations here

    (put! result-chan result))
    (recur)))

我意识到可以同时运行的线程数恰好是CPU内核数。那么在这种情况下,如果我要创建8个以上的thread或go-block,则go-block和thread是否没有区别?

我可能想在自己的笔记本电脑上模拟性能差异,但是生产环境与模拟环境完全不同。我无法得出任何结论。

顺便说一句,计算不是那么繁重。如果输入不是很大,则可以在1秒内运行8,000个循环。

另一个要考虑的因素是,阻塞执行与thread是否会影响GC性能。

1 个答案:

答案 0 :(得分:0)

这里有几点要注意。

首先,通过clojure.core.async / thread在其上创建线程的线程池是所谓的缓存线程池,这意味着尽管它将在该池中重新使用最近使用的线程,但它实际上是不受限制的。当然,这意味着如果不加以检查,它可能会占用大量系统资源。

但是考虑到您在每个异步进程中所做的工作都很轻巧,所以对我来说线程似乎有点过大。当然,考虑到您期望击中输入流的项目数量也很重要,如果这个数字很大,您可能会淹没core.async的go宏的线程池,可能到了我们等待的地步可用线程。

您也没有提到要从何处获取输入值,是在程序启动时保持不变的固定数据集输入,还是从某些源不断将输入馈入输入流中随着时间的推移?

如果是前者,那么我建议您更倾向于换能器,并且我认为CSP模型不适合您的问题,因为您不是在程序中各个单独组件之间建立通信模型,而是只是并行处理数据。

如果是后者,那么我想您还有其他进程正在监听结果通道,并对这些结果做一些重要的事情,在这种情况下,我认为您使用go-blocks是完全可以接受的。