在R中,矢量化与并行化的区别

4
作为一个玩具例子,假设我们有一个名为“my_func”的函数(代码如下),它需要两个参数“n”和“p”。“my_func”将生成一个具有“n”行和“p”列的随机矩阵“x”,并在运行时和内存使用方面执行一些昂贵的操作,比如计算“x”的奇异值之和。(当然,该函数只有一行,但我在这里追求可读性。)
my_func <- function(n, p) {
  x <- replicate(p, rnorm(n))
  sum(svd(x)$d)
}

如果我们希望对“my_func”的几个值进行计算,并且对于每个“n”的值,我们有几个“p”的值,则将函数向量化,然后将其应用于组合到“my_func”是很简单的:

n <- 10 * seq_len(5)
p <- 100 * seq_len(10)
grid <- expand.grid(n = n, p = p)
my_func <- Vectorize(my_func)
set.seed(42)
do.call(my_func, grid)
[1]   98.61785  195.50822  292.21575  376.79186  468.13570  145.18359
[7]  280.67456  421.03196  557.87138  687.75040  168.42994  340.42452
[13]  509.65528  683.69883  851.29063  199.08474  400.25584  595.18311
[19]  784.21508  982.34591  220.73215  448.23698  669.02622  895.34184
[25] 1105.48817  242.52422  487.56694  735.67588  976.93840 1203.25949

注意,对于大的 'n' 和 'p'(例如尝试 n = 1000 和 p = 2000),每次调用'my_func'都可能非常缓慢。
现在,在我的实际应用程序中,使用类似构造的函数时,'grid'中的行数比此处给出的要多得多。因此,我正在尝试更好地了解R中的向量化。
第一个问题:在上面的示例中,是否按顺序执行对'my_func'的调用,以便在下一次调用之前回收垃圾内存?我经常使用向量化,但从未停下来问这个问题。
第二个问题:(这个问题可能取决于第一个问题)假设调用次数足够多,并且'my_func'足够慢,这里是否需要并行处理?我假设是的。我的真正问题是:如果'my_func'改为为每次调用传递相同的大矩阵会怎样?为了论证,假设矩阵名为'y',有1000行和5000列,并且是即时计算的。当然,将矩阵'y'传递到每个并行节点将会产生一些滞后。
我理解第二个问题的答案可能是“取决于...”如果是这种情况,请告诉我,我将尝试提供更多细节。
此外,我感激任何建议、反馈或OMFG WTF N00B YOU HAVEN'T SEEN THIS OTHER OBSCURE SOMEWHAT RELEVANT DISCUSSION??!!!111oneone1
1个回答

8
第一个问题的答案非常明确:R中几乎所有的东西默认都是串行的。(有极少数内部会开始使用OpenMP,但引擎作为单线程可能会保持不变)。
所以对于第二个问题:是的,请尝试一下。我不经常使用Vectorize(),但我喜欢*apply()家族。用lapply()解决它,然后加载multicore包,并使用mclapply()在你拥有的所有核心上运行它。以下是一个例子:
R> system.time(res <- lapply(1:nrow(grid), 
+                            function(i) my_func(grid[i,1],grid[i,2])))
   user  system elapsed 
  0.470   0.000   0.459 
R> system.time(res <- mclapply(1:nrow(grid), 
+                              function(i) my_func(grid[i,1], grid[i,2])))
   user  system elapsed 
  0.610   0.140   0.135 
R> 

注意现在经过的时间已经是原来的29%(=0.135/0.459)。
从这里开始,您可以进一步推广并在多台计算机上进行并行执行 - 使用R进行高性能计算中的任务视图有更多指针。预计于10月31日发布的R 2.14.0将具有一个新的“parallel”软件包,它将结合multicoresnow的部分功能。

谢谢回复。我一直在使用Rmpi并行foreach,最多可使用512个核心,并通过8核框架上的multicore进行操作。虽然它提供了一个易于使用的并行计算接口,并允许我为不同机器上的不同配置编写一次,但不知道发生了什么会引起一些头痛。 - ramhiser
我经常使用*apply()系列函数,所以我会尝试一下mclapply。对于每个有8个核心的多机集群,您有什么想法吗?此外,snow(甚至是snowfall)是否可以通过更改后端轻松编写一次代码,然后将其移植到另一个配置中?看来我有些东西要去尝试一下了。 - ramhiser
Dirk - R 2.14.0中的“parallel”包是否支持Windows?(请说是,请说是=) - Suraj
是的,但是......它无法克服某些Windows限制,因此多核仍然有点棘手。Ripley教授添加了相当多的文档,您可以在其中找到更多细节。 - Dirk Eddelbuettel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接