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

Чтение глобальных переменных с использованием foreach в R

Я пытаюсь запустить цикл foreach на сервере Windows с 16-ядерным процессором и 64 ГБ оперативной памяти с использованием RStudio. (с использованием пакета doParallel)

"Рабочие" процессы копируют все переменные из цикла for (наблюдаются при просмотре создания экземпляров этих процессов в диспетчере задач Windows при запуске цикла foreach), тем самым вздувая память, используемую каждым процессом. Я попытался объявить некоторые из особенно больших переменных глобальными, гарантируя, что эти переменные также были прочитаны и не записаны внутри цикла foreach, чтобы избежать конфликтов. Тем не менее, процессы все еще быстро используют всю доступную память.

Существует ли механизм для обеспечения того, чтобы "рабочие" процессы не создавали копии некоторых переменных "только для чтения"? Например, конкретный способ объявления таких переменных?

4b9b3361

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