Подтвердить что ты не робот

Многоядерность и использование памяти в 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))
))
4b9b3361

Ответ 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, и кажется, что каждый дочерний процесс копирует таблицу данных.