理解并行计算:r future为什么会启动比workers多得多的线程?

r的future包提供了一种实现多线程并行计算的接口,但有时候在使用时,我发现r启动了比我设定的多得多的计算资源。

简单举一个例子:

代码语言:javascript
复制
data = data.table(
  v1 = rnorm(1e8),
  v2 = sample(LETTERS, size = 1e8, replace = TRUE)
)

library(future.apply)
plan(multisession, workers = 10)
rv = future_lapply(split(data, data$v2), function(x) {

data.table(
mean = mean(x$v1),
sd = sd(x$v1)
)
})
rv

上面我启用了10个线程(workers)对数据进行处理,但实际运行的时候CPU的资源图可以会类似下面这样:

有时候计算很密集的话,系统的全部CPU都会被占满。

在很久之前我就问过future包的作者,讨论在:Issue #343 · HenrikBengtsson/future

R语言大神任坤做了一段非常好的解释:

理解起来就是:

  1. 首先问题不是出在future上面,它只是一个管理器之类的东西,启动并行资源最后收集结果。
  2. 问题的核心在于R很多包或者底层库在你不知道的情况下启动了并行计算,例如data.table。举一个例子就是,如果你指定了4个worker,你只想使用4个CPU核心计算,但如果并行计算的内容函数使用了像data.table包的操作,而默认情况下data.table为了加速计算会使用系统全部的核心数目(假设一共20)。也就是你启动的每一个并行计算内容下都会使用全部的CPU核心数运算(4x20 >> 20),自然系统的资源都被占满了。

如@mxblsdl展示的例子,就可以手动进行设定解决这样的问题,即并行计算的函数开头设定仅只使用单线程(这样就变成了 4x1 = 4)。