Pada artikel terakhir , saya berbicara tentang apa itu multithreading dan memberikan contoh penerapannya dalam bahasa R ketika bekerja dengan Yandex.Direct API menggunakan doSNOW
, doParallel
dan konstruksi foreach
.
Artikel ini merupakan kelanjutan, tetapi dapat dianggap sebagai panduan offline untuk multithreading di R. Saya diminta untuk menulisnya dengan komentar yang diterima di bagian pertama (di sini terima kasih khusus kepada Alexey_mosc , SatCat , Ananiev_Genrih ), di mana saya diberi sejumlah paket yang mewakili pendekatan yang lebih modern untuk implementasi multithreading di R, kita akan membicarakannya nanti.

Isi
Tantangan
Sebagai contoh, kami mengambil masalah yang dipertimbangkan dalam publikasi sebelumnya , yaitu dalam mode multi-utas, kumpulkan daftar kata kunci dari 4 akun iklan Yandex.Direct.
Untuk bekerja dengan Yandex.Direct API, kami akan menggunakan paket ryandexdirect
. Dokumentasi resmi untuk itu ada di tautan , tetapi untuk implementasi tugas yang dijelaskan, kita hanya perlu 2 fungsi:
yadirAuth
- otorisasi di Yandex.Direct API;yadirGetKeyWords
- Unduh daftar kata kunci dari akun iklan.
Bukan saja saya memilih proses mengunduh kata kunci, faktanya adalah ini adalah salah satu operasi yang paling panjang di Yandex.Direct API. Kedua, di semua akun jumlah kata kunci berbeda, oleh karena itu, waktu untuk menyelesaikan operasi ini untuk setiap akun akan sangat berbeda, dalam kasus kami dari 1 hingga 20 detik.
Persiapan
Awalnya, Anda perlu menginstal semua paket yang dibahas dalam artikel ini, untuk ini Anda dapat menggunakan kode di bawah ini.
Kode 1: Instalasi Paket # install.packages("ryandexdirect") install.packages("tictoc") install.packages("rbenchmark") install.packages("dplyr") install.packages("purrr") install.packages("future") install.packages("promises") install.packages("furrr") install.packages("future.apply")
Agar fungsi-fungsi paket tersedia untuk Anda, Anda harus menghubungkannya menggunakan perintah library
. Untuk kenyamanan, saya akan secara terpisah menghubungkan semua paket yang diperlukan dalam setiap contoh kode yang diberikan.
Kami membuat vektor yang terdiri dari login Yandex.Direct, dari mana nanti kami akan meminta kata kunci:
Kode 2: Membuat Vektor Login logins <- c("login1", "login2", "login3", "login4")
Untuk bekerja dengan Yandex.Direct API, Anda harus terlebih dahulu melalui otorisasi di bawah setiap akun, untuk ini Anda dapat menggunakan desain berikut:
Kode 3: Otorisasi di Yandex.Direct API lapply(logins, function(l) { yadirAuth(Login = l)})
Setelah menjalankan kode di atas, browser akan terbuka untuk otorisasi di bawah setiap akun. Anda mengonfirmasi izin untuk ryandexdirect
untuk mengakses materi iklan Anda. Anda akan diarahkan ke halaman tempat Anda perlu menyalin kode verifikasi. Dengan memasukkannya ke konsol R, selesaikan proses otorisasi. Operasi ini diulangi untuk setiap login yang Anda tentukan saat membuat login vektor.
Beberapa pengguna, selama proses otorisasi, mungkin bingung dengan fakta pengalihan ke sumber daya pihak ketiga, tetapi tidak ada bahaya pada akun Anda dalam hal ini, saya menjelaskan topik ini secara lebih rinci dalam artikel "Seberapa Aman Menggunakan Paket R untuk Bekerja dengan API Sistem Periklanan" .
Selanjutnya, kami akan mempertimbangkan beberapa contoh implementasi tugas yang dijelaskan. Masing-masing akan dimulai dengan kode contoh, dan penjelasan selanjutnya. Saya pikir opsi ini akan paling nyaman untuk persepsi.
Contoh solusi pemrosesan serial, fungsi sapply dan paket purrr

Pada artikel terakhir , saya mengutip solusi menggunakan for
sebagai contoh. Karena kami menganggap multithreading menggunakan paket foreach
, yang sintaksisnya menyerupai loop, contoh ini sesuai di sana, meskipun penggunaan loop tidak disambut oleh pengguna R.
Paket-paket yang akan kita bahas dalam artikel ini lebih mengingatkan pada fungsi-fungsi keluarga yang berlaku dalam sintaksis, oleh karena itu, saya akan memberikan contoh solusi dalam mode serial menggunakannya.
Fungsi sapply
Untuk memperkirakan waktu eksekusi perintah, dalam setiap pendekatan yang dipertimbangkan, kami akan menggunakan paket tictoc
.
Kode 4: Contoh solusi dalam mode berurutan menggunakan fungsi sapply library(tictoc) library(dplyr) tic() # kw.sapply <- sapply( logins, # , function(x) # # { yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = FALSE # ) toc() # # result.sapply <- do.call("rbind", kw.sapply)
Waktu 39.36 sec elapsed
: 39.36 sec elapsed
Pada awalnya, sintaks fungsi dari keluarga yang apply
tidak semudah dibaca sebagai sintaks dari loop, tetapi pada kenyataannya semuanya cukup sederhana.
sapply(X, FUN)
Dimana:
- X - Objek yang elemen-elemennya akan kita iterate dan gunakan secara bergantian pada setiap iterasi, dalam
for
loop terlihat seperti ini: for(i in X)
; - FUN - Fungsi di mana kita akan mengganti setiap elemen dari objek X secara bergantian, jika kita menggambar analogi dengan
for
, maka ini adalah tubuh loop.
Dalam Contoh Kode 4 , vektor login yang dibuat sebelumnya diteruskan ke argumen X. Setiap elemen vektor login diteruskan sebagai satu-satunya argumen ke fungsi function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }
anonim function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }
yang diteruskan ke argumen FUN .
Yaitu sapply
akan menjalankan fungsi yang ditentukan dalam FUN 4 kali, mengganti loginnya satu per satu, dan mengembalikan hasilnya dalam bentuk daftar (objek daftar kelas) yang terdiri dari 4 elemen. Setiap elemen adalah tabel dengan daftar kata kunci yang diterima dari akun pada setiap iterasi.
yadirGetKeyWords(Login = "login1") %>% mutate(login = "login1")
yadirGetKeyWords(Login = "login2") %>% mutate(login = "login2")
yadirGetKeyWords(Login = "login3") %>% mutate(login = "login3")
yadirGetKeyWords(Login = "login4") %>% mutate(login = "login4")
Objek yang diperoleh menggunakan sapply
memiliki struktur sebagai berikut:
summary(kw.sapply)
Length Class Mode login1 19 data.frame list login2 19 data.frame list login3 19 data.frame list login4 19 data.frame list
Pada akhir contoh ini, perintah result.sapply <- do.call("rbind", kw.sapply)
menggabungkan semua 4 elemen dari daftar kw.sapply ke dalam satu frame result.sapply .
# A tibble: 6,804 x 1 result.sapply$Id $Keyword $AdGroupId $CampaignId $ServingStatus $State <dbl> <fct> <dbl> <int> <fct> <fct> 1 15164230566 ~ 3597453985 39351725 ELIGIBLE ON 2 15164230567 ~ 3597453985 39351725 ELIGIBLE ON 3 15164230568 ~ 3597453985 39351725 ELIGIBLE ON 4 15164230569 ~ 3597453985 39351725 ELIGIBLE ON 5 15164230570 ~ 3597453985 39351725 ELIGIBLE ON 6 15164230571 ~ 3597453985 39351725 ELIGIBLE ON 7 15164230572 ~ 3597453985 39351725 ELIGIBLE ON 8 15164230573 ~ 3597453985 39351725 ELIGIBLE ON 9 15164230574 ~ 3597453985 39351725 ELIGIBLE ON 10 15164230575 ~ 3597453985 39351725 ELIGIBLE ON # ... with 6,794 more rows, and 13 more variables: $Status <fct>, # $StrategyPriority <fct>, $StatisticsSearchImpressions <int>, # $StatisticsSearchClicks <int>, $StatisticsNetworkImpressions <int>, # $StatisticsNetworkClicks <lgl>, $UserParam1 <chr>, $UserParam2 <chr>, # $ProductivityValue <lgl>, $ProductivityReferences <lgl>, $Bid <dbl>, # $ContextBid <dbl>, $login <chr>
Selain sapply
, keluarga *apply
fungsi meliputi: apply
, lapply
, vapply
, mapply
, dan lainnya.
Paket purrr
Kode 5: Contoh solusi menggunakan fungsi paket purrr library(purrr) library(dplyr) library(tictoc) tic() # result.purrr <- map_df( logins, # , ~ # function(.x) { yadirGetKeyWords(Login = .x) %>% mutate(login = .x) } ) toc() #
Waktu 35.46 sec elapsed
: 35.46 sec elapsed
Paket purrr
adalah bagian dari inti dari perpustakaan tidyverse
, ditulis oleh Headley Wickham.
Dalam hal makna dan sintaksis, fungsi utama dari paket sangat mirip dengan sapply
, keuntungan utamanya adalah sebagai berikut:
- Fungsi dibagi menjadi
map
keluarga, map2
, pmap
, walk
dan sebagainya, fungsi terpisah yang termasuk dalam keluarga yang sama mengembalikan hasilnya dalam format yang berbeda: chr , dbl , int , df , dll; - Fungsi keluarga
map2
Anda untuk map2
elemen (iterate) secara bersamaan dari dua objek; - Fungsi keluarga
pmap
Anda untuk secara bersamaan pmap
ke elemen dari sejumlah objek. Anda dapat mengirimkan tabel ke input ke argumen .l (analog dari argumen X dengan sapply) , yang masing-masing kolomnya akan berisi nilai-nilai yang Anda gunakan untuk mengulangi, dan yang nantinya akan diganti menjadi argumen dengan fungsi yang sama dengan yang dilewatkan .f (analog FUN dari sapply) .
Dalam situasi apa kita perlu mengulangi elemen dari beberapa objek. Misalnya, Anda bekerja dengan beberapa akun agen, dan akun iklan tempat Anda ingin mendapatkan daftar kata kunci tersebar di antara mereka. Dalam hal ini, Anda dapat membuat vektor dari nama akun agen, dan beralih di atasnya, bersamaan dengan cara Anda menyortir login akun iklan.
Kode 6: Contoh bekerja dengan banyak akun agen library(purrr) # agencies <- c("agency1", NA, "agency2", "agency1") # # result.pmap2 <- map2_df(.x = logins, .y = agencies, ~ { yadirGetKeyWords(Login = .x, AgencyAccount = .y) %>% mutate(login = .x) })
Sekarang bayangkan situasi ketika Anda login di bawah akun yang berbeda, Anda menyimpan file dengan kredensial di folder yang berbeda, maka Anda harus segera beralih pada tiga objek: login akun iklan, login akun agen, jalur di mana file dengan kredensial disimpan. Ini bisa dilakukan dengan bantuan. pmap
keluarga pmap
.
Kode 7: contoh fungsi pmap library(purrr) # , # TokenPath <- c("C:\\proj1\\tokens", "C:\\yandex\\token", "C:\\yandex\\token", "C:\\my_yandex_acoount") # pmap.result <- pmap_df(list(Login = logins, AgencyAccount = agencies, TokenPath = TokenPath), yadirGetKeyWords)
Dengan demikian, hasil dari mengeksekusi fungsi map_df
, map2_df
dan pmap_df
adalah bingkai tanggal, dan ketika menggunakannya, langkah terakhir dari contoh dengan sapply
( do.call("rbind", kw.sapply)
) tidak diperlukan.
Kode tersebut menjadi lebih ringkas dan dieksekusi sedikit lebih cepat, namun demikian, baik pendekatan yang diuraikan, sapply
dan purrr
, mengumpulkan kata kunci dari setiap akun secara berurutan. Oleh karena itu, total waktu pelaksanaan operasi ini sama dengan jumlah durasi pengumpulan data dari keempat akun.
Waktu [total] = Waktu [login1] + Waktu [login2] + Waktu [login3] + Waktu [login4]
Opsi multithreaded untuk menyelesaikan tugas mengumpulkan kata kunci dari Yandex.Direct

Jadi, jika Anda sudah membaca artikel pertama , maka Anda tahu bahwa mode operasi multithreaded memiliki beberapa fitur:
- Setiap utas dimulai dalam sesi R yang terpisah dengan lingkungan kerja yang bersih.
- Untuk alasan yang sama, dalam proses berjalan yang terpisah, paket yang terhubung sebelumnya tidak dikirimkan secara default.
Mengekspor objek yang dibuat dalam lingkungan kerja, dan menghubungkan paket dalam setiap pendekatan diimplementasikan secara berbeda, maka kami akan mempertimbangkannya secara lebih rinci.
Paket parallel
Paket ini pertama kali dimasukkan dalam paket R dalam versi 2.14.0 dan hingga hari ini hadir dengan R itu sendiri.
Kode 8: Contoh solusi untuk masalah melalui paket paralel library(parallel) library(tictoc) # cl <- makeCluster(4) # clusterExport(cl = cl, varlist = "logins") # , # , ryandexdirect clusterEvalQ(cl = cl, { library(ryandexdirect) library(dplyr) } ) tic() # parallel.kw <- parSapplyLB(cl = cl, # X = logins, # , FUN = function(x) { # # X yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = F) # toc() # # stopCluster(cl) # result.parallel <- dplyr::bind_rows(parallel.kw)
16.75 sec elapsed
Time: 16.75 sec elapsed
Mari kita coba menguraikan Kode 8 . Fungsi makeCluster
membuat sekelompok 4 proses. Kita dapat mengekspor objek dari lingkungan kerja utama kita ke cluster yang dibuat menggunakan fungsi clusterExport
, untuk ini kita perlu menggunakan argumennya:
- cl - Cluster dimana kita akan mengekspor objek
- varlist - Vektor teks yang berisi nama-nama objek yang akan diekspor ke setiap proses cluster.
Salah satu cara untuk menghubungkan paket yang tepat pada setiap node cluster adalah dengan menggunakan fungsi clusterEvalQ
. Dalam contoh kami, kami menggunakannya untuk menghubungkan paket, tetapi Anda dapat menulis kode R apa pun di dalam clusterEvalQ
, dan itu akan diluncurkan pada awal setiap node cluster. Argumen untuk fungsi ini cukup jelas, Anda perlu menentukan cluster dan perintah yang akan dieksekusi di dalamnya.
parSapplyLB
adalah versi paralel dari fungsi sapply
dengan load balancing antara node cluster, mereka juga menggunakannya, tetapi Anda perlu menentukan cluster dengan argumen cl .
Juga secara parallel
ada versi paralel lain dari *apply
fungsi keluarga: parLapply
, parSapply
, parApply
, dll.
parSapply
berbeda dari parSapplyLB
hanya karena parSapplyLB
tidak memiliki load balancing pada node cluster.
Fungsi stopCluster
digunakan untuk menghentikan cluster yang dibuat.
Perintah terakhir, dplyr::bind_rows(parallel.kw)
kami menggabungkan objek parallel.kw yang diperoleh dengan menggunakan parSapplyLB
menjadi satu tabel.
Untuk Linux, parallel
memiliki fungsi terpisah: mclapply
, mcmapply
, mcMap
. Seringkali dalam sistem operasi ini, perintah dieksekusi lebih cepat, dan kode menjadi lebih kompak.
Kode 9: Solusi menggunakan mclapply untuk Linux library(parallel) library(tictic) library(dplyr) library(ryandexdirect) tic() mclapply.kw <- mclapply(logins, FUN = function(x) { # # X yadirGetKeyWords(Login = x) %>% mutate(login = x) }, mc.cores = 4) toc()
Saat menggunakan fungsi-fungsi ini, tidak perlu memulai cluster menggunakan makeCluster
. jumlah node yang Anda tentukan menggunakan argumen mc.cores . Juga tidak perlu menghubungkan paket dan mengekspor objek, operasi ini dilakukan secara otomatis.
Paket future
Salah satu pendekatan paling modern untuk pemrograman asinkron dalam R.
Kode yang secara paralel akan menyelesaikan masalah kita dengan bantuan future
cukup rumit untuk dipahami. Karena itu, mari kita menganalisis kerjanya pada contoh yang lebih sederhana, kami akan meminta daftar kata kunci dari satu akun.
Kode 10: Contoh paling sederhana untuk menggunakan paket yang akan datang library(future) # plan(multiprocess) # # future.kw <- future({yadirGetKeyWords(Login = logins[4])}, packages = "ryandexdirect", globals = "logins") # resolved(future.kw) # future.result.1 <- value(future.kw)
Mari kita coba mencari tahu contoh kode 10 . Fungsi plan
memungkinkan Anda untuk mengatur dan mengubah mode eksekusi dari ekspresi yang diberikan, berikut adalah yang utama:
- sequential - Ini adalah mode operasi R yang biasa; perintah dieksekusi berurutan di sesi saat ini;
- multisession - Mode paralel, perintah akan dieksekusi dalam sesi berjalan di latar belakang pada mesin saat ini, sementara sesi kerja Anda tidak akan diblokir;
- cluster - Mode paralel, perintah akan dieksekusi pada mesin saat ini atau jarak jauh, mirip dengan bagaimana itu diterapkan dalam paket
parallel
.
Seluruh paket future
didasarkan pada mengeksekusi perintah dalam proses latar belakang tanpa memblokir sesi saat ini. Jalankan eksekusi perintah mengikuti fungsi nama yang sama di future
, jadi ketika kita menjalankan perintah:
future({yadirGetKeyWords(Login = logins[4])}, packages = "ryandexdirect", globals = "logins")
Sesi kami saat ini di R tidak diblokir, dan perintah dijalankan di latar belakang, menjalankan sesi R lainnya.
Anda dapat memeriksa status saat ini dari proses eksekusi dari ekspresi yang diberikan menggunakan fungsi yang resolved
. Akhirnya, fungsi value
digunakan untuk mendapatkan hasil eksekusi di future
. Jika Anda menjalankan fungsi value
lebih awal dari menjalankan future
Anda dalam sesi berjalan paralel, maka sesi kerja saat ini akan diblokir sampai ekspresi sesi paralel selesai.
Contoh pekerjaan yang paling maju adalah penggunaan future
hubungannya dengan promises
- promises
.
Kode 11: Contoh berbagi paket `masa depan` dan` janji` library(future) library(promises) # plan(multiprocess) # # future.kw <- future({suppressMessages( yadirGetKeyWords(Login = logins[4]))}, packages = "ryandexdirect", globals = "logins") %...>% # future, # nrow() %...>% paste("words loaded") %...>% print()
Paket promises
memberikan satu set operator pipa yang sempurna melengkapi fungsionalitas future
.
Pada contoh Kode 11 , di latar belakang, kami memulai proses mengunduh kata kunci dari satu akun iklan. Selanjutnya, operator pipa %...>%
tanpa memblokir sesi kerja menunggu future
, dan melakukan operasi yang tersisa. Sebagai hasil dari eksekusi kode, setelah menyelesaikan pekerjaan di future
, jumlah kata kunci dari akun yang ditentukan akan ditampilkan di konsol:
[1] "1855 words loaded"
Di akhir artikel, contoh yang lebih ilustratif tentang sekelompok future
dan promises
akan ditunjukkan.
Secara default, paket yang future
itu sendiri mengekspor seluruh ruang kerja ke setiap sesi berjalan paralel, tetapi Anda sendiri dapat menentukan daftar objek untuk diekspor menggunakan argumen global .
Untuk menghubungkan paket ke future
harus melewati vektor yang berisi nama mereka ke argumen paket .
Sekarang kembali ke tugas kita, contoh kode berikut dalam mode paralel akan memuat daftar kata kunci dari 4 akun:
Kode 12: Contoh pemecahan masalah dengan menggunakan paket yang akan datang library(future) library(tictoc) # plan("multisession", workers = 4) tic() # futs <- lapply(logins, # function(i) # # future({ yadirGetKeyWords(Login = i) %>% mutate(login = i) }, packages = c("ryandexdirect", "dplyr"))) completed <- sapply(futs, resolved) # kw <- lapply(futs, value) # toc() # # result.future <- dplyr::bind_rows(kw)
Waktu Pimpin: 14.83 sec elapsed
Untuk mengunduh daftar kata kunci dalam mode multi-utas dari semua akun iklan yang tercantum dalam login vektor , Anda harus menjalankan future
terpisah di latar belakang. Dalam Contoh Kode 12, kami menerapkan ini menggunakan fungsi lapply
.
Hasil dari kerja lapply
adalah daftar peluncuran di future
. Anda dapat memeriksa status masing-masing menggunakan perintah sapply(futs, resolved)
, yang akan mengembalikan vektor logis tempat TRUE akan berarti future
terpenuhi, dan SALAH bahwa future
sedang berlangsung.
Untuk mendapatkan hasil dari setiap future
, setelah pekerjaan mereka selesai, kami menggunakan perintah lapply(futs, value)
.
: result.future <- dplyr::bind_rows(kw)
.
future
, (
future
), .
future.apply
future.apply
future
, .
13: future.apply library(future.apply) library(tictoc) # plan("multisession", workers = 4) tic() # kw.future.apply <- future_sapply(logins, # , function(x) { # yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = FALSE, # # future.packages = c("ryandexdirect", "dplyr"), future.globals = TRUE ) toc() #
: 17.28 sec elapsed
13 , future.apply
future
, .
4 : plan("multisession", workers = 4)
.
future_sapply
logins . Yaitu , , sapply
, .
future_sapply
future.packages . future.globals . , .
furrr
future
. purrr
, furrr
.
14: furrr library(furrr) library(tictoc) # cl <- parallel::makeCluster(4) plan(cluster, workers = cl) tic() # furrr.kw <- future_map(logins, ~ # function(.x) yadirGetKeyWords(Login = .x) %>% mutate(login = .x), .options = future_options(packages = c("ryandexdirect", "dplyr"), globals = c())) toc() # # result.furrr <-dplyr::bind_rows(furrr.kw)
: 15.45 sec elapsed
furrr
purrr
. purrr
, .
.options . .options future_options
, .
14 packages globals :
.options = future_options(packages = c("ryandexdirect", "dplyr"), globals = c())
rbenchmark
.
, future
promises
. .
, 20 4 () .
= (T[1] * 20) + (T[2] * 20) + (T[N] * 20)
15: future promises library(furrr) library(parallel) library(dplyr) library(future) library(ryandexdirect) library(tictoc) library(rbenchmark) # logins <- c("login1", "login2", "login3", "login4") # # par par.furrr <- function(logins) { cl <- parallel::makeCluster(4) plan(cluster, workers = cl) furrr.kw <- future_map(logins, ~ yadirGetKeyWords(Login = .x) %>% mutate(login = .x), .options = future_options(packages = c("ryandexdirect", "dplyr"), globals = c())) result.furrr <-dplyr::bind_rows(furrr.kw) } par.future <- function(logins) { plan("multisession", workers = 4) futs <- lapply(logins, function(i) future({ yadirGetKeyWords(Login = i) %>% mutate(login = i) }, packages = c("ryandexdirect", "dplyr"))) completed <- sapply(futs, resolved) kw <- lapply(futs, value) result.future <- dplyr::bind_rows(kw) } par.future.apply <- function(logins) { plan("multisession", workers = 4) kw.future.apply <- future_sapply(logins, function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = FALSE, future.packages = c("ryandexdirect", "dplyr"), future.globals = TRUE ) result.future.apply <- dplyr::bind_rows(kw.future.apply) } par.parallel <- function(logins) { cl <- parallel::makeCluster(4) clusterExport(cl = cl, varlist = "logins") clusterEvalQ(cl = cl, { library(ryandexdirect) library(dplyr) } ) parallel.kw <- parSapplyLB(cl = cl, X = logins, FUN = function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = F) stopCluster(cl) result.parallel <- dplyr::bind_rows(parallel.kw) } # seq seq.apply <- function(logins) { kw.sapply <- sapply( logins, function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }, simplify = FALSE ) result.sapply <- do.call("rbind", kw.sapply) } seq.purrr <- function(logins) { kw.purrr <- map_df( logins, ~ { yadirGetKeyWords(Login = .x) %>% mutate(login = .x) } ) result.purrr <- do.call("rbind", kw.purrr) } # rbenchmark # future + promises # , # plan(list(tweak(multisession, workers = 2), tweak(multisession, workers = 4))) tic() speed.test <- future({ # within(benchmark(furrr = par.furrr(logins), future = par.future(logins), future.apply = par.future.apply(logins), parallel = par.parallel(logins), apply = seq.apply(logins), purrr = seq.purrr(logins), replications = c(20), columns = c('test', 'replications', 'elapsed'), order = c('elapsed', 'test')), { average = round(elapsed/replications, 2) }) }, packages = c("dplyr", "ryandexdirect", "rbenchmark", "parallel", "purrr", "future", "promises", "furrr", "future.apply"), globals = c("logins", "par.furrr", "par.future", "par.future.apply", "par.parallel", "seq.apply", "seq.purrr")) %...>% print() %...T>% toc() message("My Session is not blocked")
3370 , .. .
. , future
, promises
, .
, . "My Session is not blocked", , , .. .
promises
:
%...>%
— %>%
, . Yaitu , resolved
, future
, value
. , print
.%...T>%
— %T>%
, , . , , , .. .. print
, , .- %...T!% — .
15 plan
tweak
( plan(list(tweak(multisession, workers = 2), tweak(multisession, workers = 4)))
), , 2 , future
4 .
:
My Session is not blocked test replications elapsed average 4 parallel 20 393.02 19.65 1 furrr 20 402.09 20.10 2 future 20 431.19 21.56 3 future.apply 20 432.29 21.61 5 apply 20 847.77 42.39 6 purrr 20 864.19 43.21 3370.55 sec elapsed

, parallel
, . furrr
, future
future.apply
.
1 , , . , API . .
, 4 , .
Kesimpulan
R, API.
, API . " R , 1" .
:
- doSNOW / doParallel + foreach
- future + promises
- future.apply / furrr
- parallel
, , .
, R .