for r foreach parallel-processing

Guardando mĂșltiples salidas de foreach dopar loop



for in r (3)

Este ejemplo de juguete muestra cómo devolver múltiples resultados de un bucle% dopar%.

Este ejemplo:

  • Gira hasta 3 núcleos.
  • Representa una gráfica de cada núcleo.
  • Devuelve el gráfico y un mensaje adjunto.
  • Imprime los gráficos y se adjunta mensaje.

Encontré esto realmente útil para acelerar el uso de Rmarkdown para imprimir 1,800 gráficos en un documento PDF.

Probado bajo Windows 10 , RStudio y R v3.3.2 .

Código R:

# Demo of returning multiple results from a %dopar% loop. library(foreach) library(doParallel) library(ggplot2) cl <- makeCluster(3) registerDoParallel(cl) # Create class which holds multiple results for each loop iteration. # Each loop iteration populates two properties: $resultPlot and $resultMessage. # For a great tutorial on S3 classes, see: # http://www.cyclismo.org/tutorial/R/s3Classes.html#creating-an-s3-class plotAndMessage <- function(resultPlot=NULL,resultMessage="?") { me <- list( resultPlot = resultPlot, resultMessage = resultMessage ) # Set the name for the class class(me) <- append(class(me),"plotAndMessage") return(me) } oper <- foreach(i=1:5, .packages=c("ggplot2")) %dopar% { x <- c(i:(i+2)) y <- c(i:(i+2)) df <- data.frame(x,y) p <- ggplot(df, aes(x,y)) p <- p + geom_point() message <- paste("Hello, world! i=",i,"/n",sep="") result <- plotAndMessage() result$resultPlot <- p result$resultMessage <- message return(result) } # Print resultant plots and messages. Despite running on multiple cores, # ''foreach'' guarantees that the plots arrive back in the original order. foreach(i=1:5) %do% { # Print message attached to plot. cat(oper[[i]]$resultMessage) # Print plot. print(oper[[i]]$resultPlot) } stopCluster(cl)

Me gustaría saber si / cómo sería posible devolver múltiples salidas como parte del bucle foreach dopar .

Tomemos un ejemplo muy simplista. Supongamos que me gustaría hacer 2 operaciones como parte del bucle foreach , y me gustaría devolver o guardar los resultados de ambas operaciones para cada valor de i .

Para que solo se devuelva una salida, sería tan simple como:

library(foreach) library(doParallel) cl <- makeCluster(3) registerDoParallel(cl) oper1 <- foreach(i=1:100000) %dopar% { i+2 }

oper1 sería una lista con 100000 elementos, cada elemento es el resultado de la operación i+2 para cada valor de i.

Supongamos que ahora me gustaría devolver o guardar los resultados de dos operaciones diferentes por separado, por ejemplo, i+2 e i+3 . Intenté lo siguiente:

oper1 = list() oper2 <- foreach(i=1:100000) %dopar% { oper1[[i]] = i+2 return(i+3) }

esperando que los resultados de i+2 se guarden en la lista oper1 , y que oper1 los resultados de la segunda operación i+3 . Sin embargo, ¡nada se llena en la lista oper1 ! En este caso, solo el resultado de i+3 se devuelve del bucle.

¿Hay alguna forma de devolver o guardar ambas salidas en dos listas separadas?


No intente utilizar efectos secundarios con foreach o cualquier otro paquete de programa paralelo. En su lugar, devuelva todos los valores del cuerpo del bucle foreach en una lista. Si desea que su resultado final sea una lista de dos listas en lugar de una lista de 100,000 listas, especifique una función de combinación que trasponga los resultados:

comb <- function(x, ...) { lapply(seq_along(x), function(i) c(x[[i]], lapply(list(...), function(y) y[[i]]))) } oper <- foreach(i=1:10, .combine=''comb'', .multicombine=TRUE, .init=list(list(), list())) %dopar% { list(i+2, i+3) } oper1 <- oper[[1]] oper2 <- oper[[2]]

Tenga en cuenta que esta función de combinación requiere el uso del argumento .init para establecer el valor de x para la primera invocación de la función de combinación.


Prefiero usar una clase para mantener varios resultados para un bucle% dopar%.

Este ejemplo combina 3 núcleos, calcula múltiples resultados en cada núcleo y luego devuelve la lista de resultados al hilo de llamada.

Probado bajo RStudio , Windows 10 y R v3.3.2 .

library(foreach) library(doParallel) # Create class which holds multiple results for each loop iteration. # Each loop iteration populates two properties: $result1 and $result2. # For a great tutorial on S3 classes, see: # http://www.cyclismo.org/tutorial/R/s3Classes.html#creating-an-s3-class multiResultClass <- function(result1=NULL,result2=NULL) { me <- list( result1 = result1, result2 = result2 ) ## Set the name for the class class(me) <- append(class(me),"multiResultClass") return(me) } cl <- makeCluster(3) registerDoParallel(cl) oper <- foreach(i=1:10) %dopar% { result <- multiResultClass() result$result1 <- i+1 result$result2 <- i+2 return(result) } stopCluster(cl) oper1 <- oper[[1]]$result1 oper2 <- oper[[1]]$result2