4

In R, the mcparallel() function in the parallel package forks off a new task to a worker each time it is called. If my machine has N (physical) cores, and I fork off 2N tasks, for example, then each core starts off running two tasks, which is not desirable. I would rather like to be able to start running N tasks on N workers, and then, as each tasks finishes, submit the next task to the now-available core. Is there an easy way to do this?

My tasks take different amounts of time, so it is not an option to fork off the tasks serial in batches of N. There might be some workarounds, such as checking the number of active cores and then submitting new tasks when they become free, but does anyone know of a simple solution?

I have tried setting cl <- makeForkCluster(nnodes=N), which does indeed set N cores going, but these are not then used by mcparallel(). Indeed, there appears to be no way to feed cl into mcparallel(). The latter has an option mc.affinity, but it's unclear how to use this and it doesn't seem to do what I want anyway (and according to the documentation its functionality is machine dependent).

4

2 回答 2

2

你至少有两种可能性:

  1. 如上所述,您可以使用 mcparallel 的参数“mc.cores”或“mc.affinity”。在 AMD 平台上,“mc.affinity”是首选,因为两个内核共享相同的时钟。例如,FX-8350 有 8 个内核,但内核 0 与内核 1 具有相同的时钟。如果您只为 2 个内核启动任务,最好将其分配给内核 0 和 1 而不是 0 和 2。“mc.affinity “做到这一点。代价是失去负载平衡。

    “mc.affinity”出现在该软件包的最新版本中。查看更新日志以了解何时引入。

  2. 您也可以使用操作系统的工具来设置亲和力,例如“taskset”:

    /usr/bin/taskset -c 0-1 /usr/bin/R ...

    在这里,您使脚本仅在核心 0 和 1 上运行。

请记住,Linux 的内核编号从“0”开始。并行包符合 R 的索引,第一个核心是核心编号 1。

于 2014-05-01T11:43:41.797 回答
0

我建议并行利用包含此功能的高级函数,而不是试图强制低级函数执行您想要的操作。

在这种情况下,请尝试将您的任务编写为单个函数的不同参数。然后,您可以使用 mclapply(),并将 mc.preschedule 参数设置为 TRUE,并将 mc.cores 参数设置为一次要使用的线程数。每次任务完成并且线程关闭时,都会创建一个新线程,对下一个可用任务进行操作。

即使每个任务使用完全不同的代码,您也可以创建一个函数列表并将其传递给包装函数。例如,以下代码一次执行两个函数。

f1 <- function(x) {x^2}
f2 <- function(x) {2*x}
f3 <- function(x) {3*x}
f4 <- function(x) {x*3}
params <- list(f1,f2,f3,f4)
wrapper <- function(f,inx){f(inx)}
output <- mclapply(params,FUN=calling,mc.preschedule=TRUE,mc.cores=2,inx=5)

如果需要,您可以将 params 设为一个列表列表,其中包括要传递给每个函数的各种参数以及函数定义。我经常将这种方法用于不同长度的各种任务,并且效果很好。

当然,也有可能你的各种任务只是对同一个函数的不同调用,这种情况下你可以直接使用 mclapply 而无需编写包装函数。

于 2014-04-15T18:38:13.930 回答