Параллельный вызов внешней программы с использованием foreach и doSNOW: как импортировать результаты?
Я использую R для параллельного вызова внешней программы в кластере с несколькими узлами и несколькими ядрами. Внешняя программа требует три файла входных данных и создает один выходной файл (все файлы хранятся в одной подпапке). Чтобы запустить программу параллельно (или, скорее, вызвать ее параллельно), я изначально использовал foreach
функционировать вместе с doParallel
библиотека. Это прекрасно работает, пока я использую несколько ядер на одном узле.
Однако я хотел использовать несколько узлов с несколькими ядрами. Поэтому я изменил свой код соответственно, чтобы использовать doSNOW
библиотека в сочетании с foreach
(Я старался Rmpi
а также doMPI
, но мне не удалось запустить код на нескольких узлах с этими библиотеками). Это работает нормально, т.е. внешняя программа теперь действительно выполняется на нескольких узлах (с несколькими ядрами), и файл журнала кластера показывает, что она дает требуемые результаты. Однако проблема, с которой я сейчас сталкиваюсь, заключается в том, что внешняя программа больше не хранит файлы результатов / выходных данных на главном узле / в указанной подпапке рабочего каталога (так было, когда я использовал doParallel
). Это лишает меня возможности импортировать результаты в R.
Действительно, если я проверяю содержимое соответствующей папки, она не содержит никаких выходных файлов, несмотря на то, что файл журнала ясно показывает, что внешняя программа успешно запущена. Я думаю, они хранятся на разных узлах (?). Какие изменения я должен сделать, чтобы мой foreach
функция или способ, которым я настроил свой кластер, чтобы эти файлы сохранялись на главном узле / в указанной подпапке в моем рабочем каталоге?
Вот пример кода R, чтобы продемонстрировать, что я делаю:
# #Set working directory in non-interactive mode
setwd(system("pwd", intern = T))
# #Load some libraries
library(foreach)
library(parallel)
library(doParallel)
# ####Parallel tasks####
# #Create doSNOW cluster for parallel tasks
library(doSNOW)
nCoresPerNode <- as.numeric(Sys.getenv("PBS_NUM_PPN"))
nodeNames <- system("cat $PBS_NODEFILE | uniq", intern=TRUE)
machines <- rep(nodeNames, each = nCoresPerNode)
cl <- makeCluster(machines, type = "SOCK")
registerDoSNOW(cl)
# #How many workers are we using?
getDoParWorkers()
#####DUMMY CODE#####
# #The following 3 lines of code are just dummy code:
# #The idea is to create input files for the external program "myprogram"
external_Command_Script.cmd # #command file necessary for external program "myprogram" to run
startdata # #some input data for "myprogram"
enddata # #additional input data for "myprogram"
####DUMMY CODE######
# #Write necessary command and data files for external program: THIS WORKS!
for(i in 1:100)){
write(external_Command_Script.cmd[[i]], file=paste("./mysubfolder/external_Command_Script.",i,".cmd", sep=""))
write.table(startdata, file=paste("./mysubfolder/","startdata.",i,".txt", sep=""), col.names = FALSE, quote=FALSE)
write.table(enddata, file=paste("./mysubfolder/","enddata.",i,".txt", sep=""), col.names = FALSE, quote=FALSE)
}
# #Run external program "myprogram" in parallel: THIS WORKS!
foreach(i = 1:100)) %dopar% {
system(paste('(cd ./mysubfolder && ',"myprogram",' ' ,"enddata.",i,".txt ", "startdata.",i,".txt", sep="",' < external_Command_Script.',i,'.cmd)'))
}
# #Import results of external program: THIS DOES NOT WORK WHEN RUN ON MULTIPLE NODES!
results <- list()
for(i in 1:100)){
results[[i]] = read.table(paste("./mysubfolder/","enddata.txt.",i,".log.txt", sep=""), sep = "\t", quote="\"", header = TRUE)
}
# #The import does NOT work as the files created by the external program are NOT stored on the master node/in the
# #subfolder of the working directory!
# #Instead I get the following error message:
# #sh: line 0: cd: ./mysubfolder: No such file or directory
# #Error in { : task 6 failed - "cannot open the connection"
Мой скрипт pbs для кластера выглядит примерно так:
#!/bin/bash
# request resources:
#PBS -l nodes=2:ppn=8
#PBS -l walltime=00:30:00
module add languages/R-3.3.3-ATLAS
export PBS_O_WORKDIR="/panfs/panasas01/gely/xxxxxxx/workingdirectory"
# on compute node, change directory to 'submission directory':
cd $PBS_O_WORKDIR
# run your program and time it:
time Rscript ./R_script.R
2 ответа
Проблема решена: я допустил ошибку: внешняя программа на самом деле НЕ работает - я неверно истолковал файл журнала. Причина, по которой внешняя программа не запускается, заключается в том, что подпапка (содержащая необходимые входные данные) не найдена. Похоже, что кластером по умолчанию является каталог пользователя, а не рабочий каталог, указанный в сценарии отправки pbs. Это поведение отличается от кластеров, созданных с doParallel
, которые действительно распознают рабочий каталог. Поэтому проблема решается простым добавлением относительного пути к рабочему каталогу и подпапке в R-скрипте, т.е. ./workingdirectory/mysubfolder/
вместо просто ./mysubfolder/
, Кроме того, вы также можете использовать полный путь к папке.
Я хотел бы предложить вам посмотреть пакет batchtools. Предоставляет методы взаимодействия с TORQUE / PBS от R.
Если какое-то время вы можете использовать его предшественник BatchJobs, я бы также рекомендовал попробовать это, и когда вы поймете, как это работает, загляните в foreF адаптер doFuture. Это позволит вам использовать пакет future.BatchJobs. Эта комбинация doFuture, future.BatchJobs и BatchJobs позволяет вам делать все изнутри R, и вам не нужно беспокоиться о создании временных R-скриптов и т. Д. (Отказ от ответственности: я являюсь автором обоих).
Пример того, как это будет выглядеть, когда вы его настроите:
## Tell foreach to use futures
library("doFuture")
registerDoFuture()
## Tell futures to use TORQUE / PBS with help from BatchJobs
library("future.BatchJobs")
plan(batchjobs_torque)
и тогда вы используете:
res <- foreach(i = 1:100) %dopar% {
my_function(pathname[i], arg1, arg2)
}
Это оценит каждую итерацию в отдельном задании PBS, т.е. вы увидите 100 заданий, добавленных в очередь.
У будущих виньеток "БатчДжобс" есть больше примеров и информации.
ОБНОВЛЕНИЕ 2017-07-30: Пакет future.batchtools находится на CRAN с мая 2017 года. Этот пакет теперь рекомендуется в будущем. BatchJobs. Использование очень похоже на выше, например, вместо plan(batchjobs_torque)
вы сейчас используете plan(batchtools_torque)
,