Чтение глобальных переменных с помощью foreach в R
Я пытаюсь запустить цикл foreach на Windows-сервере с 16-ядерным процессором и 64 ГБ оперативной памяти, используя RStudio. (используя пакет doParallel)
"Рабочие" процессы копируют все переменные извне цикла for (это наблюдается при наблюдении за созданием этих процессов в диспетчере задач Windows при выполнении цикла foreach), что приводит к раздуванию памяти, используемой каждым процессом. Я попытался объявить некоторые из особенно больших переменных глобальными, при этом следя за тем, чтобы эти переменные также считывались, а не записывались в цикле foreach, чтобы избежать конфликтов. Тем не менее, процессы по-прежнему быстро используют всю доступную память.
Существует ли механизм, обеспечивающий, чтобы "рабочие" процессы не создавали копии некоторых переменных "только для чтения"? Как конкретный способ объявить такие переменные?
1 ответ
doParallel
Пакет будет автоматически экспортировать переменные для рабочих, на которые есть ссылки в foreach
петля. Если вы не хотите этого делать, вы можете использовать foreach
Опция ".noexport", чтобы предотвратить автоматический экспорт определенных переменных. Но если я вас правильно понимаю, ваша проблема в том, что R впоследствии дублирует некоторые из этих переменных, что является еще большей проблемой, чем обычно, поскольку это происходит в нескольких процессах на одной машине.
Нет способа объявить переменную, чтобы R никогда не создавал ее дубликат. Вам либо нужно заменить проблемные переменные объектами из пакета, например bigmemory
так что копии никогда не создаются, или вы можете попробовать изменить код таким образом, чтобы не вызвать дублирование. Вы можете использовать tracemem
функция, чтобы помочь вам, так как он будет печатать сообщение всякий раз, когда этот объект дублируется.
Однако вы можете избежать этой проблемы, сократив объем данных, необходимых работникам. Это уменьшает объем данных, которые необходимо скопировать каждому из сотрудников, а также уменьшает объем их памяти.
Вот классический пример предоставления работникам больше данных, чем им нужно:
x <- matrix(1:100, 10)
foreach(i=1:10, .combine='c') %dopar% {
mean(x[,i])
}
Поскольку матрица x
упоминается в foreach
Цикл, он будет автоматически экспортирован для каждого из работников, даже если каждому работнику требуется только подмножество столбцов. Самое простое решение состоит в том, чтобы выполнять итерации по фактическим столбцам матрицы, а не по индексам столбцов:
foreach(xc=x, .combine='c') %dopar% {
mean(xc)
}
Мало того, что рабочим передается меньше данных, но каждому рабочему фактически нужно иметь только один столбец в памяти за раз, что значительно уменьшает его объем памяти для больших матриц. xc
вектор может по-прежнему дублироваться, но это не так больно, потому что он намного меньше, чем x
,
Обратите внимание, что этот метод помогает только тогда, когда doParallel
использует "производные от снега" функции, такие как parLapply
а также clusterApplyLB
, не при использовании mclapply
, Использование этой техники может сделать цикл немного медленнее, когда mclapply
используется, так как все работники получают матрицу x
бесплатно, так зачем переносить по колонкам, когда у рабочих уже есть вся матрица? Однако в Windows doParallel
не может использовать mclapply
, так что эта техника очень важна.
Важно подумать о том, какие данные действительно нужны работникам для выполнения своей работы, и попытаться уменьшить их, если это возможно. Иногда вы можете сделать это с помощью специальных итераторов, либо из iterators
или же itertools
пакеты, но вы также можете сделать это, изменив свой алгоритм.