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

欢迎!请参阅关于页面,了解更多关于这是如何工作的信息。

0
Clojure

pmap的代码为需要执行的一组map操作创建future,然后以显然意图保持任意时刻只有#CPUs+2个未完成的future被实现的方式作用于该序列。对于非分块输入seq,它正是这样工作的,但当pmap接收到一个分块seq时,future序列也会变成分块的。这导致由于#CPUs+2窗口和块大小窗口的交互,发生了任意数量的future被实现。

pmap的文档字符串并没有承诺任何特定的并行级别,但我觉得分块和非分块输入不一致的并行级别构成了一个bug。

8 个答案

0

评论由:stu发表

下一个人深入研究pmap时可能也需要考虑fork/join。

0

评论由:jim.blomo发表

fork/join是Java 7的一个特性。如果提出的补丁需要能够回退到Java 5特性,怎么办?

0

评论者:jafingerhut

Clojure/core 成员可以更加权威地说,但据我所知,随着最近对 jsr166 代码的 reduce 功能增强,Clojure 1.5 很可能需要 Java 6 或更高版本,Java 5 将不再受支持。

0

评论由:jim.blomo发表

当任务受CPU限制时,同时启动比CPU核心更多的线程不是一个好主意。目前(1.4)pmap 使用一个无界的线程池,因此分块序列将创建比预期更多的线程。最低侵入性变更是使用固定大小的线程池(例如ForkJoinPool)。pmap 与 core.reducers 区别在于它是懒的。这意味着它是按顺序一次提交一个线程 Pool 的模型,而不是递归的 fork/join 模型。权衡包括

在分块序列上强制预览
- 无需更改线程池
- 违背分块,这可能是出于某种原因而使用的

迁移到固定大小线程池
- 减少分块序列上 CPU 密集型函数的竞争
- 增加 I/O 密集型函数的总实现时间

使用 ForkJoinPool 作为固定线程池(而不是 newFixedThreadPool)
- 自动和动态并行性
- - 更复杂的设置(选择 Java 6 与 7 实现,与 core.reducers 共享池)

我认为使用传统的固定大小线程池是正确的选择。大部分时间,pmap 的所有结果都将被实现,因此我认为严格限制预览大小不值得。这也是 map 所做的决定。因为我们没有利用 ForkJoin 的主要优势(递归工作队列),我认为在 clojure.core 中设置它不值得。

我将使用 Agent/pooledExecutor 作为固定大小线程。

如果我不小心或误解了什么,请告诉我。

0

评论由:jim.blomo发表

2012年5月28日的 pmap-chunking-862.diff 使用固定大小线程池为 pmap 函数。

0

评论者:jafingerhut

2012年5月28日的补丁 pmap-chunking-862.diff 在 2014年1月11日 Clojure master 上最新提交后不再适用。我认为唯一问题是添加的测试已改变上下文行,所以如果有人想更新补丁的话,应该是一个快速修复。

0

评论由:jim.blomo发表

感谢更新,Andy。这个月我将尝试解决这个问题。

0
参考: https://clojure.atlassian.net/browse/CLJ-862(由llasram报告)
...