Многоядерность и использование памяти в R под Ubuntu
Я запускаю R на рабочей станции Ubuntu с 8 виртуальными ядрами и 8 ГБ RAM. Я надеялся регулярно использовать многоядерный пакет для одновременного использования 8 ядер; однако я считаю, что весь процесс R дублируется 8 раз.
Поскольку на самом деле R, похоже, использует гораздо больше памяти, чем указано в gc (в 5 раз, даже после gc()), это означает, что даже относительно мягкое использование памяти (один объект 200 Мб) становится неумолимо тяжелым в памяти, раз дублируется 8 раз,
Я заглянул в bigmemory, чтобы дочерние процессы имели одинаковое пространство памяти; но для этого потребуется некоторое серьезное переписывание моего кода, поскольку оно не касается файлов данных.
Есть ли способ сделать R максимально возможным, как можно раньше, перед разветвлением, т.е. заставить ОС восстановить как можно больше памяти?
EDIT:
Кажется, я понимаю, что происходит сейчас. Проблема не в том, где я думал, что это - объекты, которые существуют в родительском потоке и не управляются, не дублируются восемь раз. Вместо этого моя проблема, я полагаю, исходила из характера манипуляции, которую я делаю, чтобы каждый дочерний процесс выполнялся. Каждый из них должен манипулировать большим фактором с сотнями тысяч уровней, и я думаю, что это бит памяти. В результате, действительно, общая загрузка памяти пропорциональна количеству ядер; но не так драматично, как я думал.
Еще один урок, который я узнал, заключается в том, что с 4-мя физическими ядрами + возможностью гиперпоточности гиперпоточность на самом деле обычно не является хорошей идеей для R. Прирост минимален, а стоимость памяти может быть нетривиальной. Итак, теперь я буду работать с 4 ядрами.
Для тех, кто хочет экспериментировать, это тип кода, который я запускал:
# Create data
sampdata <- data.frame(id = 1:1000000)
for (letter in letters) {
sampdata[, letter] <- rnorm(1000000)
}
sampdata$groupid = ceiling(sampdata$id/2)
# Enable multicore
library(multicore)
options(cores=4) # number of cores to distribute the job to
# Actual job
system.time(do.call("cbind",
mclapply(subset(sampdata, select = c(a:z)), function(x) tapply(x, sampdata$groupid, sum))
))
Ответы
Ответ 1
Вы пробовали data.table?
> system.time(ans1 <- do.call("cbind",
lapply(subset(sampdata,select=c(a:z)),function(x)tapply(x,sampdata$groupid,sum))
))
user system elapsed
906.157 13.965 928.645
> require(data.table)
> DT = as.data.table(sampdata)
> setkey(DT,groupid)
> system.time(ans2 <- DT[,lapply(.SD,sum),by=groupid])
user system elapsed
186.920 1.056 191.582 # 4.8 times faster
> # massage minor diffs in results...
> ans2$groupid=NULL
> ans2=as.matrix(ans2)
> colnames(ans2)=letters
> rownames(ans1)=NULL
> identical(ans1,ans2)
[1] TRUE
Ваш пример очень интересный. Он достаточно большой (200 МБ), существует много групп (1/2 миллиона), и каждая группа очень маленькая (2 строки). Вероятно, 191-е годы могут быть улучшены довольно много, но, по крайней мере, это начало. [Март 2011]
И теперь эта идиома (т.е. lapply(.SD,...)
) была улучшена. С v1.8.2 и на более быстром компьютере, чем выше, и с последней версией R и т.д., Приведенное ниже сравнение:
sampdata <- data.frame(id = 1:1000000)
for (letter in letters) sampdata[, letter] <- rnorm(1000000)
sampdata$groupid = ceiling(sampdata$id/2)
dim(sampdata)
# [1] 1000000 28
system.time(ans1 <- do.call("cbind",
lapply(subset(sampdata,select=c(a:z)),function(x)
tapply(x,sampdata$groupid,sum))
))
# user system elapsed
# 224.57 3.62 228.54
DT = as.data.table(sampdata)
setkey(DT,groupid)
system.time(ans2 <- DT[,lapply(.SD,sum),by=groupid])
# user system elapsed
# 11.23 0.01 11.24 # 20 times faster
# massage minor diffs in results...
ans2[,groupid:=NULL]
ans2[,id:=NULL]
ans2=as.matrix(ans2)
rownames(ans1)=NULL
identical(ans1,ans2)
# [1] TRUE
sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-pc-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252
attached base packages:
[1] stats graphics grDevices datasets utils methods base
other attached packages:
[1] data.table_1.8.2 RODBC_1.3-6
Ответ 2
Вещи, которые я пробовал на Ubuntu 64 бит R, ранжированы в порядке успеха:
-
Работайте с меньшим количеством ядер, как вы это делаете.
-
Разделите задания mclapply на части и сохраните частичные результаты в базе данных с помощью DBI с append = TRUE.
-
Используйте функцию rm
вместе с gc()
часто
Я пробовал все это, и mclapply все еще начинает создавать все большие и большие процессы по мере его запуска, что заставляет меня подозревать, что каждый процесс держится за какую-то остаточную память, в которой он действительно не нужен.
P.S. Я использовал data.table, и кажется, что каждый дочерний процесс копирует таблицу данных.