foreach 非常慢,有大量值
foreach very slow with large number of values
我正在尝试使用 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)
out1
和 out2
花了很长时间才达到 运行。只要我保持它们 运行ning,它们甚至都不会产生多个线程。 out3
几乎立即生成线程并且 运行 非常快。 foreach
是否在进行某种不能很好扩展的初始处理?如果是这样,是否有简单的解决方法?我真的更喜欢 foreach
的语法。
我还应该注意到,我尝试并行化的实际代码比 1+1 复杂得多。我仅将此作为示例展示,因为即使使用这个简单的代码,foreach 似乎也在做一些非常慢的预处理。
forach/doParallel 小插图说(代码比你的小得多):
Note well that this is not a practical use of doParallel. This is our
“Hello, world” program for parallel computing. It tests that
everything is installed and set up properly, but don’t expect it to
run faster than a sequential for loop, because it won’t! sqrt executes
far too quickly to be worth executing in parallel, even with a large
number of iterations. With small tasks, the overhead of scheduling the
task and returning the result can be greater than the time to execute
the task itself, resulting in poor performance. In addition, this
example doesn’t make use of the vector capabilities of sqrt, which it
must to get decent performance. This is just a test and a pedagogical
example, not a benchmark.
所以您的设置可能不是更快。
改为尝试不使用并行化但使用矢量化:
q <- sapply(1:1e6, function(x) 1 + 1 )
它与您的示例循环完全相同,并且在一秒钟内完成。
现在试试这个(它仍然在同一时间做完全相同的事情:
x <- rep(1, n=1e6)
r <- x + 1
它立即添加到 1e6 1
s 一个 1
。 (矢量化的力量...)
根据我的个人经验,foreach
与 doParallel
的组合比使用存储库 Bioconda 中的生物信息学 BiocParallel
包要慢得多。 (我是一名生物信息学家,在生物信息学领域,我们经常有大量计算的东西,因为我们有几千兆字节的单个数据文件要处理——而且其中很多)。
我使用 BiocParallel
尝试了您的函数,它使用了所有分配的 CPU 100%(在作业执行期间由 运行 htop
测试)整个过程花费了 17 秒。
当然 - 对于您的轻量级示例,这适用:
the overhead of scheduling the task and returning the result
can be greater than the time to execute the task itself
总之,好像比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。
查看 bioconductor 它提供了多少个包,并且都有详细的记录。
我希望这对你未来的并行计算有所帮助。
我正在尝试使用 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)
out1
和 out2
花了很长时间才达到 运行。只要我保持它们 运行ning,它们甚至都不会产生多个线程。 out3
几乎立即生成线程并且 运行 非常快。 foreach
是否在进行某种不能很好扩展的初始处理?如果是这样,是否有简单的解决方法?我真的更喜欢 foreach
的语法。
我还应该注意到,我尝试并行化的实际代码比 1+1 复杂得多。我仅将此作为示例展示,因为即使使用这个简单的代码,foreach 似乎也在做一些非常慢的预处理。
forach/doParallel 小插图说(代码比你的小得多):
Note well that this is not a practical use of doParallel. This is our “Hello, world” program for parallel computing. It tests that everything is installed and set up properly, but don’t expect it to run faster than a sequential for loop, because it won’t! sqrt executes far too quickly to be worth executing in parallel, even with a large number of iterations. With small tasks, the overhead of scheduling the task and returning the result can be greater than the time to execute the task itself, resulting in poor performance. In addition, this example doesn’t make use of the vector capabilities of sqrt, which it must to get decent performance. This is just a test and a pedagogical example, not a benchmark.
所以您的设置可能不是更快。
改为尝试不使用并行化但使用矢量化:
q <- sapply(1:1e6, function(x) 1 + 1 )
它与您的示例循环完全相同,并且在一秒钟内完成。 现在试试这个(它仍然在同一时间做完全相同的事情:
x <- rep(1, n=1e6)
r <- x + 1
它立即添加到 1e6 1
s 一个 1
。 (矢量化的力量...)
根据我的个人经验,foreach
与 doParallel
的组合比使用存储库 Bioconda 中的生物信息学 BiocParallel
包要慢得多。 (我是一名生物信息学家,在生物信息学领域,我们经常有大量计算的东西,因为我们有几千兆字节的单个数据文件要处理——而且其中很多)。
我使用 BiocParallel
尝试了您的函数,它使用了所有分配的 CPU 100%(在作业执行期间由 运行 htop
测试)整个过程花费了 17 秒。
当然 - 对于您的轻量级示例,这适用:
the overhead of scheduling the task and returning the result can be greater than the time to execute the task itself
总之,好像比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。 查看 bioconductor 它提供了多少个包,并且都有详细的记录。 我希望这对你未来的并行计算有所帮助。