评论由:jim.blomo发表
当工作受CPU限制时,多启动线程数超过CPU核心数不是一个好主意。目前(1.4版本)pmap使用了一个无限制的线程池,因此分块序列将创建比预期更多的线程。最小的侵扰性更改是使用固定大小的线程池(ForkJoinPool是一个例子)。pmap与core.reducers的区别在于它是懒加载的。这意味着它采用了一个依次提交模型的ThreadPool.submit,而不是递归的fork/join模型。权衡包括
即使在分块序列上也强制执行预读
- + 不改变threadPool
- - 反对分块,这可能是出于某种原因而被使用的
迁移到固定大小线程池
- + 减少在分块序列上对CPU密集型函数的竞争
- - 增加I/O密集型函数的总实际化时间
使用ForkJoinPool作为固定线程池(而不是newFixedThreadPool)
- + 自动和动态并行性
- - 更复杂的设置(选择Java 6与7实现,与core.reducers共享池)
我认为使用传统的固定大小线程池是正确的选择。大多数时候,pmap的所有结果都会被实现,因此我认为不值得通过严格限制预读大小来节省工作量。这也是map所做出的决定。因为我们没有使用ForkJoin的主要优势(递归工作队列),所以我认为在clojure.core中设置它是不值得的。
我将使用Agent/pooledExecutor作为固定大小的线程。
如果我有遗忘或理解错误的地方,请告知。