doParallel和foreach无法并行合并操作

时间:2014-09-26 14:36:15

标签: r foreach parallel-processing doparallel

我正在尝试将大data.frame与小的len <- 2000000 set.seed(666) dat = paste(sample(letters, len, rep = T), sample(0:9, len, rep = T), sample(letters, len, rep = T), sep = '') # create a vector of strings that are 3-long head(dat) set.seed(777) num <- sample(0:9, len, replace = T) bigDF <- data.frame(dat = dat, num = num) smallDF <- data.frame(num = 0:9, caps = toupper(letters[1:10])) startP <- 1 chunk <- 10000 nodes <- detectCores() cl <- makeCluster(nodes) registerDoParallel(cl) mergedList <- foreach(i = 0:(len/chunk - 1)) %dopar% { tmpDF = bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ] merge(tmpDF, smallDF, by = 'num', all.x = T) } stopCluster(cl) 合并,并将计算并行化。下面的代码非常完美,最大化了我机器的所有内核:

dat

一旦我将向量len <- 2000000 set.seed(666) dat = paste(sample(letters, len, rep = T), sample(0:9, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sep = '') # create a vector of strings that are 6-long head(dat) set.seed(777) num <- sample(0:9, len, replace = T) bigDF <- data.frame(dat = dat, num = num) smallDF <- data.frame(num = 0:9, caps = toupper(letters[1:10])) startP <- 1 chunk <- 10000 nodes <- detectCores() cl <- makeCluster(nodes) registerDoParallel(cl) mergedList <- foreach(i = 0:(len/chunk - 1)) %dopar% { tmpDF = bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ] merge(tmpDF, smallDF, by = 'num', all.x = T) } stopCluster(cl) 更改为包含5长的字符串,并行性就会中断,虽然没有错误或警告,但只有1个核心有助于计算:

dat

为什么会出现这种不一致,以及如何解决这个问题呢?在特定示例中,如果将{{1}}索引为整数,则代码可以正常工作。但索引并不是所有情况下的答案。为什么字符串的长度与使用的内核数量有关?

2 个答案:

答案 0 :(得分:3)

我认为不同之处在于,在第一种情况下,“bigDF”的第一列是6,760级的因子,而在第二种情况下,它有1,983,234级。具有大量级别可能会导致许多性能问题。当我使用stringsAsFactors=FALSE创建“bigDF”时,性能要好得多。

bigDF <- data.frame(dat=dat, num=num, stringsAsFactors=FALSE)

我还使用了itertools包中的“isplitRows”函数,以避免向每个worker发送所有“bigDF”:

library(itertools)
mergedList <- foreach(splitDF=isplitRows(bigDF, chunkSize=chunk)) %dopar% {
    merge(splitDF, smallDF, by = 'num', all.x = T)
}

在我运行R 3.1.1的6核Linux机器上,你的第二个例子在大约332秒内运行。当我使用stringsAsFactors=FALSE时,它会在大约50秒内运行。当我也使用isplitRows时,时间下降到5.5秒,比第二个例子快约60倍。

答案 1 :(得分:1)

还没有回答,但是: 如果我运行您的代码但使用%do%以便不进行并行化,那么除了dat名称之外,我会得到两个案例相同(成功)的结果。如果我使用%dopar%运行短名称,使用%do%运行长名称,则相同。

这开始看起来像其中一个支持包中的一个微妙的错误,所以你可能想要ping这个开发人员。

更新29Sept:我运行了我认为相同的设置但使用ClusterMap:

dffunc <-function(i=i,bigDF=bigDF,smallDF=smallDF,startP=startP,chunk=chunk) {
tmpDF <- bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ]
    merge(tmpDF, smallDF, by = 'num', all.x = T)
    }


clusmerge<- clusterMap(cl,  function(i) {dffunc(i=i)}, 0:(len/chunk-1),MoreArgs=list(bigDF=bigDF,smallDF=smallDF,startP=startP,chunk=chunk) )

在这种情况下,无论dat名称字符串的长度如何,我都会启动并运行所有节点。我回过头来怀疑%dopar%包中foreach或其他地方存在一些错误。

作为附注,我建议不要这样做

nodes <- detectCores()
cl <- makeCluster(nodes)

因为这可以挂起你的整个机器。更好cl <- makeCluster(nodes-1) :-)