parallel - Entendiendo las diferencias entre mclapply y parLapply en R
mclapply r (2)
Recientemente comencé a usar técnicas paralelas en R para un proyecto y tengo mi programa trabajando en sistemas Linux usando mclapply del paquete parallel . Sin embargo, he llegado a un parLapply
con mi comprensión de parLapply
para Windows.
Usando mclapply
puedo establecer el número de núcleos, iteraciones y pasar eso a una función existente en mi área de trabajo.
mclapply(1:8, function(z) adder(z, 100), mc.cores=4)
Parece que no puedo lograr lo mismo en Windows usando parLapply
. Como lo entiendo, necesito pasar todas las variables usando clusterExport()
y pasar la función real que quiero aplicar al argumento.
¿Es correcto o hay algo similar a la función mclapply
que es aplicable a Windows?
La belleza de mclapply
es que todos los procesos de trabajo se crean como clones del maestro justo en el punto en que se llama mclapply
, por lo que no tiene que preocuparse de reproducir su entorno en cada uno de los trabajadores de clúster. Desafortunadamente, eso no es posible en Windows.
Cuando usa parLapply
, generalmente tiene que realizar los siguientes pasos adicionales:
- Crear un clúster de PSOCK
- Registre el cluster si lo desea
- Cargar los paquetes necesarios en los trabajadores del cluster.
- Exportar los datos y funciones necesarios al entorno global de los trabajadores del clúster.
Además, cuando haya terminado, es una buena práctica cerrar el clúster de stopCluster
utilizando stopCluster
.
Aquí hay una traducción de su ejemplo a parLapply
:
library(parallel)
cl <- makePSOCKcluster(4)
setDefaultCluster(cl)
adder <- function(a, b) a + b
clusterExport(NULL, c(''adder''))
parLapply(NULL, 1:8, function(z) adder(z, 100))
Si su función de adder
requiere un paquete, tendrá que cargar ese paquete en cada uno de los trabajadores antes de llamarlo con parLapply
. Puedes hacerlo fácilmente con clusterEvalQ
:
clusterEvalQ(NULL, library(MASS))
Tenga en cuenta que el primer argumento NULL
para clusterExport
, clusterEval
y parLapply
indica que deben usar el objeto de clúster registrado a través de setDefaultCluster
. Eso puede ser muy útil si su programa usa mclapply
en muchas funciones diferentes, de modo que no tenga que pasar el objeto de clúster a todas las funciones que lo necesitan al convertir su programa para usar parLapply
.
Por supuesto, el adder
puede llamar a otras funciones en su entorno global que llaman a otras funciones, etc. En ese caso, tendrá que exportarlas también y cargar los paquetes que necesiten. También tenga en cuenta que si alguna de las variables que ha exportado cambia durante el curso de su programa, tendrá que volver a exportarlas para actualizarlas en los trabajadores del clúster. Nuevamente, eso no es necesario con mclapply
porque siempre crea / clona / bifurca a los trabajadores cada vez que se llama, haciendo que sea innecesario.
mclapply es más fácil de usar y utiliza la funcionalidad fork () del sistema operativo subyacente para lograr la paralelización. Sin embargo, dado que Windows no tiene fork (), en su lugar se ejecutará lapply estándar, sin paralelización.
ParLapply es una bestia diferente. Creará un grupo de procesos, que incluso podrían residir en diferentes máquinas en su red, y se comunican a través de TCP / IP para pasar las tareas y los resultados entre sí.
El problema en su código es que no se dio cuenta de que el primer parámetro para parLapply debería ser un objeto "agrupado". El ejemplo más simple de usar parLapply para ejecutarse en una sola máquina que se me ocurre es el siguiente:
library(parallel)
# Spawn child processes using fork() on the local machine
cl <- makeForkCluster(getOption("cl.cores", 2))
# Use parLapply to calculate lengths of 1000 strings
text = rep("Hello, world!", 1000)
len = parLapply(cl, text, nchar)
# Kill child processes since they are no longer needed
stopCluster(cl)
El uso de parLapply con un clúster creado con makeForkCluster como anteriormente es funcionalmente equivalente a llamar a mclapply. Así que tampoco funcionará en Windows. :) Mire las otras maneras en que puede crear un clúster con makeCluster y makePSOCKcluster en la documentación y verifique qué funciona mejor para sus requisitos.