评论者:jim.blomo
当工作受 CPU 限制时,启动多于 CPU 核心的线程不是一个好主意。目前(1.4)pmap 使用一个无界的线程池,因此分块的序列将创建比预期更多的线程。最不具侵略性的更改是使用固定大小的线程池(ForkJoinPool 是一个例子)。pmap 与 core.reducers 的区别在于它是惰性的。这意味着它使用一次提交一个 ThreadPool.model 的线程池,而不是递归的 fork/join 模型。权衡包括:
在分块序列上强制预览
- + 没有改变线程池
- - 与分块背道而驰,这可能是出于某种原因
切换到固定大小的线程池
- + 降低分块序列上 CPU 限制函数的竞争
- - 增加对 I/O 限制函数的总实现时间
对于固定大小的线程池使用 ForkJoinPool(而不是 newFixedThreadPool)
- + 自动和动态并行
- - 更复杂的设置(选择 Java 6 与 7 实现的版本,与 core.reducers 共享池)
我认为使用传统的固定大小线程池是正确选项。大多数时候 pmap 的所有结果都将被实现,所以我认为没有必要对预览大小进行严格要求。这也是 map 做出的决定。由于我们没有使用 ForkJoin 的主要优势(递归任务队列),我认为在 clojure.core 中设置它是没有意义的。
我将使用 Agent/pooledExecutor 作为固定大小的线程。
如果有什么遗漏或误解,请告诉我。