2013-05-05 33 views
7

我有一個非常大的字符串向量,並且想要使用foreachdosnow包進行並行計算。我注意到foreach會爲每個進程創建向量副本,因此會迅速耗盡系統內存。我試圖在列表對象中將矢量分解爲更小的部分,但仍未看到任何內存使用減少。有沒有人對此有過想法?下面是一些演示代碼:如何避免使用foreach複製對象

library(foreach) 
library(doSNOW) 
library(snow) 

x<-rep('some string', 200000000) 
# split x into smaller pieces in a list object 
splits<-getsplits(x, mode='bysize', size=1000000) 
tt<-vector('list', length(splits$start)) 
for (i in 1:length(tt)) tt[[i]]<-x[splits$start[i]: splits$end[i]] 

ret<-foreach(i = 1:length(splits$start), .export=c('somefun'), .combine=c) %dopar% somefun(tt[[i]]) 
+1

只是一個想法:當調用 'ret <-foreach(k in tt,.export = c('somefun'),.combine = c)%dopar%somefun(k) '? – Beasterfield 2013-05-05 13:27:58

+0

感謝提示,Beasterfield,但似乎'foreach'未能識別'in'語法。 – baidao 2013-05-05 13:54:48

+0

對不起,當然我的意思是'foreach(k = tt,...)'。 – Beasterfield 2013-05-05 14:10:22

回答

4

迭代的風格,你使用通常與doMC後端效果很好,因爲工人可以有效的fork神奇共享tt。但doSNOWtt將自動導出到工人,使用大量的內存,即使他們實際上只需要一小部分內存。 @Beasterfield直接通過tt進行迭代的建議解決了這個問題,但通過使用迭代器和適當的並行後端,可以提高內存的效率。

在這種情況下,我使用itertools包中的isplitVector函數。它將一個矢量分解爲一個子矢量序列,允許它們並行處理而不會失去矢量化的好處。不幸的是,在doSNOW中,爲了調用snow中的clusterApplyLB函數,它將把這些子向量放入列表中,因爲clusterApplyLB不支持迭代器。但是,doMPIdoRedis後端不會這樣做。他們會從迭代器中將子向量發送給工作人員,使用幾乎一半的內存。

下面是使用doMPI一個完整的示例:

suppressMessages(library(doMPI)) 
library(itertools) 
cl <- startMPIcluster() 
registerDoMPI(cl) 
n <- 20000000 
chunkSize <- 1000000 
x <- rep('some string', n) 
somefun <- function(s) toupper(s) 
ret <- foreach(s=isplitVector(x, chunkSize=chunkSize), .combine='c') %dopar% { 
    somefun(s) 
} 
print(length(ret)) 
closeCluster(cl) 
mpi.quit() 

當我在我的MacBook運行此臨用4 GB的內存

$ time mpirun -n 5 R --slave -f split.R 

大約需要16秒。

您必須小心在同一臺機器上創建的工作人員數量,儘管降低chunkSize的值可能會讓您開始更多工作。

如果您能夠使用不需要所有字符串同時在內存中的迭代器,則可以更多地減少內存使用量。例如,如果字符串位於名爲'strings.txt'的文件中,則可以使用s=ireadLines('strings.txt', n=chunkSize)

+0

特別是對於'ireadLines',這遵循一個管理者/工作者範式,工作者由單個經理過程產生;有沒有辦法使用'itertools',但採用更多的SPMD方式([pbdR](https://rdav.nics.tennessee.edu/2012/09/pbdr/)),以便R工人的管理留給mpirun?將流程管理的責任全部交給mpirun處理,似乎是更好的責任分工。 – 2013-05-05 18:29:40

+0

@MartinMorgan:這是一個有趣的想法。我已經使用了構建在'Rmpi'上的自己的SPMD風格的軟件包,但我沒有考慮在這種情況下使用迭代器,儘管我一直對其他上下文中的分佈式迭代器的想法感興趣。我從來沒有使用'pbdR',但我應該檢查出來。 – 2013-05-05 19:10:14