foreach非常慢,具有大量值

时间:2018-10-11 20:09:22

标签: r foreach doparallel mclapply

我正在尝试使用foreach进行并行计算。如果要迭代的值很少,则效果很好,但是在某些时候它变得非常慢。这是一个简单的示例:

library(foreach)
library(doParallel)

registerDoParallel(8)

out1 <- foreach(idx=1:1e6) %do%
    {
        1+1
    }

out2 <- foreach(idx=1:1e6) %dopar%
    {
        1+1
    }

out3 <- mclapply(1:1e6,
                 function(x) 1+1,
                 mc.cores=20)

out1out2的运行时间非常长。只要我让它们保持运行状态,它们甚至都不会产生多个线程。 out3几乎立即产生线程并非常快速地运行。 foreach是否正在执行某种无法很好扩展的初始处理?如果是这样,有没有简单的解决方法?我真的更喜欢foreach的语法。

我还应该注意,我尝试并行化的实际代码比1 + 1复杂得多。我仅以示例为例,因为即使使用此简单代码,foreach似乎仍在进行一些非常慢的预处理。

1 个答案:

答案 0 :(得分:1)

forach / doParallel小插图说(比您的代码小得多):

  

请注意,这不是doParallel的实际用法。这是我们的   用于并行计算的“ Hello,world”程序。它测试   一切都已正确安装和设置,但不要期望   比顺序for循环运行更快,因为它不会! sqrt执行   太快了,不值得并行执行,即使是大型   迭代次数。对于小型任务,安排   任务和返回结果可能大于执行时间   任务本身,导致性能不佳。另外,这个   这个例子没有利用sqrt的向量功能   必须获得体面的表现。这只是测试和教学法   例如,而不是基准。

所以设置的速度可能并不快。

请尝试不使用并行化,而是使用矢量化:

q <- sapply(1:1e6, function(x) 1 + 1 )

它的作用与示例循环完全相同,并在一秒钟内完成。 现在尝试一下(它在相同的时间执行相同的操作:

x <- rep(1, n=1e6)
r <- x + 1

它将1立即添加到1e6 1 s中。 (矢量化的力量...)

从我个人的经验来看,foreachdoParallel的结合要比使用存储库Bioconda中的生物信息学BiocParallel软件包要慢得多。 (我是一名生物信息学家,在生物信息学领域,我们经常需要进行大量计算工作,因为我们要处理的文件数据只有几GB,其中有许多GB)。 我使用BiocParallel尝试了您的功能,并且它以100%使用所有分配的CPU(通过在作业执行期间运行htop进行测试),整个过程花费了17秒。

可以肯定-适用于您的轻量级示例:

  

计划任务和返回结果的开销   可能大于执行任务本身的时间

无论如何,似乎比doParallel更充分地使用了CPU。因此,如果要完成大量计算任务,请使用此功能。 这里的代码我是怎么做到的:

# For bioconductor packages, the best is to install this:
install.packages("BiocManager")

# Then activate the installer
require(BiocManager)

# Now, with the `install()` function in this package, you can install
# conveniently Bioconductor packages like `BiocParallel`
install("BiocParallel")

# then, activate it
require(BiocParallel)

# initiate cores:
bpparam <- bpparam <- SnowParam(workers=4, type="SOCK") # 4 or take more CPUs

# prepare the function you want to parallelize
FUN <- function(x) { 1 + 1 }

# and now you can call the function using `bplapply()`
# the loop parallelizing function in BiocParallel.
s <- bplapply(1:1e6, FUN, BPPARAM=bpparam) # each value of 1:1e6 is given to 
# FUN, note you have to pass the SOCK cluster (bpparam) for the 
# parallelization

有关更多信息,请转到the vignette of the BiocParallel package。 看一下生物导体,它提供了多少个包装,并且都有完整的记录。 希望这对您将来的并行计算工作有所帮助。