Rozważmy standardu pogrupowane operację na data.frame:Zamiennik dla równoległego plyr z doMC
library(plyr)
library(doMC)
library(MASS) # for example
nc <- 12
registerDoMC(nc)
d <- data.frame(x = c("data", "more data"), g = c("group1", "group2"))
y <- "some global object"
res <- ddply(d, .(g), function(d_group) {
# slow, complicated operations on d_group
}, .parallel = FALSE)
To trywialne, aby skorzystać z konfiguracji multi-core, po prostu pisząc .parallel = TRUE
zamiast. To jedna z moich ulubionych cech plyr.
Ale z plyr są przestarzałe (chyba) i zasadniczo zastąpiony przez dplyr, Purrr itp rozwiązanie równoległe przetwarzanie stało się znacznie bardziej gadatliwy:
library(dplyr)
library(multidplyr)
library(parallel)
library(MASS) # for example
nc <- 12
d <- tibble(x = c("data", "more data"), g = c("group1", "group2"))
y <- "some global object"
cl <- create_cluster(nc)
set_default_cluster(cl)
cluster_library(cl, packages = c("MASS"))
cluster_copy(cl, obj = y)
d_parts <- d %>% partition(g, cluster = cl)
res <- d_parts %>% collect() %>% ungroup()
rm(d_parts)
rm(cl)
Można sobie wyobrazić, jak długo tego przykładem może weź pod uwagę każdy pakiet i obiekt, który potrzebujesz w pętli, i potrzebujesz jego własnej komendy cluster_*
, aby skopiować ją do węzłów. Nierównoległe tłumaczenie plyr-to-dplyr jest po prostu prostą konstrukcją dplyr::group_by
i niefortunne jest to, że nie istnieje prosty sposób na umożliwienie przetwarzania równoległego. Tak, moje pytania są:
- Czy jest to w rzeczywistości preferowany sposób tłumaczenia mojego kodu z plyr na dplyr?
- Jaki rodzaj magii dzieje się za kulisami w plyr, co sprawia, że tak łatwo włączyć przetwarzanie równoległe? Czy istnieje powód, dla którego ta zdolność byłaby szczególnie trudna do dodania do dplyra i dlatego jeszcze nie istnieje?
- Czy moje dwa przykłady różnią się zasadniczo pod względem sposobu wykonania kodu?
Re swoim trzecim pytaniu: ja Powiedz tak. Twój przykład "plyr" używa 'doMC', czyli backendu' multicore' dla 'foreach', czyli: ** forking **. Twój przykład 'multidplyr' używa' create_cluster', który domyślnie stosuje 'parallel :: makePSOCKcluster', czyli: ** Parallel SOCKet Cluster **. –
Na drugie pytanie: ten sam rodzaj magii, który się dzieje, jeśli po prostu wywołasz 'partition()' bez wcześniejszego skonfigurowania klastra: 'plyr' opiera się na wcześniej zarejestrowanym backend' foreach' (print (plyr ::: setup_parallel)) '),' multidplyr :: partition() 'bez klastra opiera się na' create_cluster() 'niejawnie, ale prawdopodobnie wykryje inny backend, jeśli jest już zarejestrowany (nie sprawdziłem, jednak zobacz' print() multidplyr ::: cluster_exists)) '). Pierwsze przykłady winiety 'multidplyr' ilustrują tę możliwość po prostu wywoływania' partition() 'bez wcześniejszej konfiguracji. –
Na pierwsze pytanie: na tyle, na ile mogę stwierdzić, z dokumentu i z moich własnych eksperymentów, 'multidplyr' nie pozwala na rozwidlenie drogi' plyr', tylko 'PSOCK'. –