Чтение глобальных переменных с помощью 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 пакеты, но вы также можете сделать это, изменив свой алгоритм.

Другие вопросы по тегам