Крутящий момент всегда создает файл, содержащий имена узлов, которые были выделены на работе по Моава, и проходит путь этот файл к вашей работе через переменную окружения PBS_NODEFILE
. Имена узлов могут быть перечислены несколько раз, чтобы указать, что он назначил несколько ядер вашему заданию на этом узле. В этом случае мы хотим запустить работника кластера для каждого уникального имени узла в PBS_NODEFILE
, но отслеживать количество выделенных ядер на каждом из этих узлов, чтобы мы могли указать правильное количество ядер при регистрации doMC
.
Вот функция, которая считывает PBS_NODEFILE
и возвращает фрейм данных с информацией о выделенном узле:
getnodes <- function() {
f <- Sys.getenv('PBS_NODEFILE')
x <- if (nzchar(f)) readLines(f) else rep('localhost', 3)
as.data.frame(table(x), stringsAsFactors=FALSE)
}
Возвращаемый фрейм данных содержит столбец с именем «х» имен узлов и столбец с именем «Част» соответствующих значений сердечника.
Это позволяет легко создать и зарегистрировать носка кластер с одним работником на уникальный узел:
nodes <- getnodes()
cl <- makeSOCKcluster(nodes$x)
registerDoSNOW(cl)
Теперь мы можем легко выполнить foreach
цикл с одной задачи на одного работника, но это не так легко пройти правильное количество выделенных ядер каждому из этих работников, не зависящее от некоторых деталей реализации как snow
, так и doSNOW
, в частности, связанных с реализацией функции clusterApplyLB
, используемой doSNOW
. Конечно, вам легко узнать, что количество выделенных ядер одинаково на каждом узле, но это сложнее, если вы хотите общее решение проблемы.
Один (не очень элегантно) общее решение, чтобы назначить количество выделенных ядер к глобальной переменной на каждом из рабочих с помощью функции снег clusterApply
:
setcores <- function(cl, nodes) {
f <- function(cores) assign('allocated.cores', cores, pos=.GlobalEnv)
clusterApply(cl, nodes$Freq, f)
}
setcores(cl, nodes)
Это гарантирует, что значению " alloc .cores "на каждом из рабочих равно количеству раз, когда этот узел появился в PBS_NODEFILE
.
Теперь мы можем использовать эту глобальную переменную при регистрации doMC
:
r <- foreach(i=seq_along(nodes$x), .packages='doMC') %dopar% {
registerDoMC(allocated.cores)
foreach(j=1:allocated.cores, .combine='c') %dopar% {
i * j
}
}
Вот работа пример сценария, который может быть использован для выполнения этого R сценария:
#!/bin/sh
#PBS -l nodes=4:ppn=8
cd "$PBS_O_WORKDIR"
R --slave -f hybridSOCK.R
Когда это представленное с помощью команда qsub
, сценарий R создаст кластер SOCK с четырьмя рабочими, и каждый из этих рабочих будет выполнять внутренний цикл foreach
с использованием 8 ядер. Но поскольку код R является общим, он должен делать правильные вещи независимо от ресурсов, запрошенных через qsub
.
изменилось?моя система не имеет registerDoMC() или registerDoSNOW(), только registerDoParallel(). – Dominik
@ Dominik Нет, это не изменилось. Функция registerDoMC определена в пакете doMC, который зависит от параллельного пакета. –
Извините, я вижу это сейчас. Где вы устанавливаете 'cores' в своей функции' setcores'? или я должен изменить его на число? – Dominik