في المقال الأخير ، تحدثت عن ماهية تعدد مؤشرات الترابط ، وقدمت أمثلة على تنفيذه باللغة R عند العمل مع Yandex.Direct API باستخدام doParallel
والبناء foreach
.
هذه المقالة هي امتداد ، ولكن يمكن اعتبارها دليلًا دون اتصال متعدد مؤشرات الترابط في R. لقد طُلب مني كتابته بالتعليقات التي وردت في الجزء الأول (هنا شكر خاص لـ Alexey_mosc ، SatCat ، Ananiev_Genrih ) ، حيث تلقيت عددًا من الحزم التي تمثل طريقة أكثر حداثة لـ تطبيقات multithreading في R ، سنتحدث عنها لاحقًا.

محتوى
مهمة
على سبيل المثال ، نأخذ المشكلة التي تم بحثها في منشور سابق ، أي في وضع متعدد الخيوط ، اجمع قائمة بالكلمات الرئيسية من 4 حسابات إعلانية في Yandex.Direct.
للعمل مع Yandex.Direct API ، سوف نستخدم حزمة ryandexdirect
. الوثائق الرسمية الخاصة بها موجودة على الرابط ، لكن لتنفيذ المهمة الموصوفة ، نحتاج فقط إلى وظيفتين:
yadirAuth
- التفويض في Yandex.Direct API ؛yadirGetKeyWords
- قم بتنزيل قائمة بالكلمات الرئيسية من حسابات الإعلانات.
ليس فقط أنني اخترت عملية تنزيل الكلمات الرئيسية ، ولكن الحقيقة هي أن هذه واحدة من أكثر العمليات الطويلة في واجهة برمجة تطبيقات Yandex.Direct. ثانياً ، يختلف عدد الكلمات الرئيسية في جميع الحسابات ، وبالتالي ، فإن وقت إتمام هذه العملية لكل حساب سيكون مختلفًا جدًا ، في حالتنا من 1 إلى 20 ثانية.
تدريب
في البداية ، تحتاج إلى تثبيت جميع الحزم التي تمت مناقشتها في هذه المقالة ، لذلك يمكنك استخدام الكود أدناه.
الكود 1: تثبيت الحزم # 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")
لكي تكون وظائف الحزمة متاحة لك ، يجب توصيلها باستخدام أمر library
. للراحة ، سوف أقوم بتوصيل كل الحزم اللازمة بشكل منفصل في كل مثال رمز معين.
نقوم بإنشاء متجه يتكون من تسجيلات Yandex.Direct ، والتي سنطلب منها فيما بعد الكلمات الرئيسية:
الرمز 2: إنشاء ناقل تسجيل الدخول logins <- c("login1", "login2", "login3", "login4")
للعمل مع واجهة برمجة تطبيقات Yandex.Direct ، تحتاج أولاً إلى الدخول في تفويض تحت كل حساب ، لذلك يمكنك استخدام التصميم التالي:
الكود 3: التفويض في Yandex.Direct API lapply(logins, function(l) { yadirAuth(Login = l)})
بعد تشغيل الكود أعلاه ، سيفتح المتصفح للترخيص تحت كل حساب. عليك تأكيد إذن ryandexdirect
للوصول إلى المواد الإعلانية الخاصة بك. سيتم توجيهك إلى الصفحة التي تحتاج إلى نسخ رمز التحقق. بإدخاله في وحدة التحكم R ، أكمل عملية التفويض. يتم تكرار هذه العملية لكل تسجيل دخول قمت بتحديده عند إنشاء تسجيلات دخول المتجه.
قد يكون بعض المستخدمين ، أثناء عملية التفويض ، مرتبكين من حقيقة إعادة التوجيه إلى مورد تابع لجهة خارجية ، لكن لا يوجد أي خطر على حسابك في هذا الموضوع ، وقد وصفت هذا الموضوع بمزيد من التفصيل في المقالة "مدى أمان استخدام حزم R للعمل مع واجهات برمجة التطبيقات لأنظمة الإعلان" .
بعد ذلك ، سننظر في العديد من الأمثلة لتنفيذ المهمة الموصوفة. سيبدأ كل منها برمز مثال ، مع شرح إضافي. أعتقد أن هذا الخيار سيكون أكثر ملاءمة للإدراك.
مثال حل المعالجة التسلسلية ، وظيفة sapply وحزمة purrr

في المقالة الأخيرة ، ذكرت حلاً باستخدام حلقة for
كمثال. نظرًا لأننا نظرنا في تعدد العمليات باستخدام حزمة foreach
، التي تشبه بناء الجملة الحلقات ، فإن هذا المثال كان مناسبًا ، على الرغم من أن مستخدمي الحلقات لا يرحب بهم.
الحزم التي سنأخذها في الاعتبار في هذه المقالة تذكرنا بشكل أكبر بوظائف عائلة التطبيق في بناء الجملة ؛ وبالتالي ، سأقدم مثالًا على حل في الوضع التسلسلي الذي يستخدمها.
وظيفة sapply
لتقدير وقت تنفيذ الأوامر ، في كل من الطرق التي تم النظر فيها ، سوف نستخدم حزمة tictoc
.
رمز 4: مثال الحل في الوضع المتسلسل باستخدام وظيفة 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)
39.36 sec elapsed
الوقت: 39.36 sec elapsed
في البداية ، ليس من السهل قراءة بناء جملة وظائف apply
كما هو الحال في بناء الحلقات ، ولكن في الواقع ، كل شيء بسيط للغاية.
sapply(X, FUN)
حيث:
- X - كائن سوف نكرر عناصره ونستخدمه بدوره في كل تكرار ، في حلقة تبدو هذه كما يلي:
for(i in X)
؛ - FUN - هي الوظيفة التي سنستبدل فيها كل عنصر من عناصر الكائن X بدوره ، إذا رسمنا تشابهًا
for
، فهذا هو نص الحلقة.
في مثال التعليمة البرمجية 4 ، يتم تمرير ناقل تسجيل الدخول الذي تم إنشاؤه مسبقًا إلى الوسيطة X. يتم تمرير كل عنصر في متجه logins بدوره كوسيطة فقط لوظيفة function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }
المجهولة function(x) { yadirGetKeyWords(Login = x) %>% mutate(login = x) }
الذي تم تمريره إلى وسيطة FUN .
أي سيقوم sapply
بتنفيذ الوظيفة المحددة في FUN 4 مرات ، واستبدال عمليات تسجيل الدخول بها واحدة تلو الأخرى ، وإرجاع النتيجة في شكل قائمة (كائن قائمة الفئات) تتكون من 4 عناصر. كل عنصر عبارة عن جدول يحتوي على قائمة بالكلمات الرئيسية المستلمة من الحساب في كل تكرار.
yadirGetKeyWords(Login = "login1") %>% mutate(login = "login1")
yadirGetKeyWords(Login = "login2") %>% mutate(login = "login2")
yadirGetKeyWords(Login = "login3") %>% mutate(login = "login3")
yadirGetKeyWords(Login = "login4") %>% mutate(login = "login4")
يحتوي الكائن الذي تم الحصول عليه باستخدام sapply
على البنية التالية:
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
في نهاية هذا المثال ، result.sapply <- do.call("rbind", kw.sapply)
أمر result.sapply <- do.call("rbind", kw.sapply)
جميع العناصر الأربعة لقائمة kw.sapply في إطار 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>
بالإضافة إلى sapply
، تتضمن مجموعة الوظائف *apply
sapply
: lapply
، vapply
، mapply
، mapply
وغيرها.
حزمة purrr
رمز 5: مثال الحل باستخدام وظائف حزمة purrr library(purrr) library(dplyr) library(tictoc) tic() # result.purrr <- map_df( logins, # , ~ # function(.x) { yadirGetKeyWords(Login = .x) %>% mutate(login = .x) } ) toc() #
35.46 sec elapsed
الوقت: 35.46 sec elapsed
تعتبر حزمة purrr
جزءًا من قلب المكتبة tidyverse
، من تأليف هيدلي ويكهام.
من حيث المعنى وبناء الجملة ، فإن الوظائف الرئيسية للحزمة تشبه إلى حد كبير sapply
، ميزتها الرئيسية هي كما يلي:
- تنقسم الوظائف إلى
map
العائلات ، map2
، pmap
، walk
وما إلى ذلك ، الوظائف المنفصلة المضمنة في نفس العائلة تُرجع النتيجة بتنسيقات مختلفة: chr ، dbl ، int ، df ، وما إلى ذلك ؛ map2
لك وظائف عائلة map2
على العناصر (التكرار) في وقت واحد map2
؛pmap
لك وظائف عائلة pmap
في وقت واحد على عناصر أي عدد من الكائنات. يمكنك تمرير جدول إلى المدخلات إلى الوسيطة .l (تناظرية للوسيطة X في sapply) ، وسيحتوي كل عمود منها على القيم التي ستكررها ، والتي سيتم استبدالها بدورها في وسيطات نفس الوظيفة التي تم تمريرها في .f (تمثيلي FUN من رقيق) .
في أي موقف نحتاج إلى التكرار على عناصر متعددة الأشياء. على سبيل المثال ، أنت تعمل مع العديد من حسابات الوكلاء ، وحسابات الإعلان التي تريد الحصول على قائمة بالكلمات الرئيسية مبعثرة بينها. في هذه الحالة ، يمكنك إنشاء ناقل من أسماء حسابات الوكلاء ، والتكرار فوقه ، بالتوازي مع كيفية فرز معلومات تسجيل الدخول إلى حسابات الإعلانات.
الرمز 6: مثال على العمل مع حسابات الوكلاء المتعددة library(purrr) # agencies <- c("agency1", NA, "agency2", "agency1") # # result.pmap2 <- map2_df(.x = logins, .y = agencies, ~ { yadirGetKeyWords(Login = .x, AgencyAccount = .y) %>% mutate(login = .x) })
الآن تخيل الموقف الذي عند قيامك بتسجيل الدخول تحت حسابات مختلفة ، قمت بحفظ الملف باستخدام بيانات الاعتماد في مجلدات مختلفة ، فأنت بحاجة إلى التكرار فورًا على ثلاثة كائنات: تسجيلات حسابات الإعلان ، وتسجيلات حسابات الوكيل ، والمسار الذي يتم تخزين الملف به بيانات الاعتماد. يمكن القيام بذلك بمساعدة. pmap
الأسرة pmap
.
رمز 7: مثال 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)
وفقًا لذلك ، فإن نتيجة تنفيذ الدالات map_df
و map2_df
و pmap_df
هي إطار التاريخ ، وعند استخدامها ، فإن الخطوة الأخيرة من المثال مع sapply
( do.call("rbind", kw.sapply)
) غير مطلوبة.
أصبحت الشفرة أكثر sapply
ونفذت بشكل أسرع قليلاً ، ولكن مع ذلك ، فإن كلا من الأساليب الموصوفة ، sapply
و purrr
، تجمع الكلمات الرئيسية من كل حساب بالتسلسل. لذلك ، فإن وقت التنفيذ الكلي لهذه العملية يساوي مجموع فترات جمع البيانات من الحسابات الأربعة.
الوقت [الإجمالي] = الوقت [login1] + الوقت [login2] + الوقت [login3] + الوقت [login4]
خيارات متعددة مؤشرات الترابط لحل مهمة تجميع الكلمات الرئيسية من Yandex.Direct

لذلك ، إذا كنت قد قرأت بالفعل المقالة الأولى ، فأنت تعلم أن وضع التشغيل متعدد مؤشرات الترابط يحتوي على العديد من الميزات:
- يبدأ كل مؤشر ترابط في جلسة R منفصلة مع بيئة عمل نظيفة.
- للسبب نفسه ، في عملية تشغيل منفصلة ، لا يتم إرسال الحزم المتصلة مسبقًا افتراضيًا.
يتم تنفيذ تصدير الكائنات التي تم إنشاؤها في بيئة العمل ، وربط الحزم في كل نهج بطريقة مختلفة ، ثم سننظر فيها بمزيد من التفصيل.
حزمة parallel
تم تضمين هذه الحزمة لأول مرة في حزمة R في الإصدار 2.14.0 وحتى يومنا هذا تأتي مع R نفسها.
رمز 8: مثال الحل للمشكلة من خلال الحزمة الموازية 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
الوقت: 16.75 sec elapsed
دعنا نحاول تحليل الكود 8 . makeCluster
الدالة makeCluster
مجموعة من 4 عمليات. يمكننا تصدير الكائنات من بيئة العمل الرئيسية الخاصة بنا إلى الكتلة التي تم إنشاؤها باستخدام دالة clusterExport
، ولهذا نحتاج إلى استخدام الوسائط الخاصة بها:
- cl - الكتلة التي سنقوم بتصدير الكائنات إليها
- varlist - متجه نص يحتوي على أسماء الكائنات التي سيتم تصديرها إلى كل عملية نظام مجموعة.
طريقة واحدة للاتصال الحزم الصحيحة على كل عقدة نظام المجموعة هي استخدام الدالة clusterEvalQ
. في مثالنا ، نستخدمها لتوصيل الحزم ، ولكن يمكنك كتابة أي رمز R داخل clusterEvalQ
، وسيتم إطلاقه في بداية كل عقدة نظام المجموعة. الوسائط الخاصة بهذه الوظيفة واضحة إلى حد ما ، تحتاج إلى تحديد الكتلة والأوامر التي سيتم تنفيذها فيها.
parSapplyLB
هو نسخة متوازية من وظيفة sapply
مع موازنة التحميل بين عقد الكتلة ، كما أنها تستخدمها ، ولكن تحتاج إلى تحديد الكتلة مع وسيطة cl .
أيضًا على parallel
هناك إصدارات متوازية أخرى من *apply
وظائف الأسرة: parLapply
، parSapply
، parApply
، إلخ.
يختلف parSapply
عن parSapplyLB
فقط لأنه لا يحتوي على موازنة تحميل على عقد نظام المجموعة.
يتم استخدام الدالة stopCluster
لإيقاف الكتلة التي تم إنشاؤها.
الأمر الأخير ، dplyr::bind_rows(parallel.kw)
نقوم بدمج الكائن parallel.kw الذي تم الحصول عليه باستخدام parSapplyLB
في جدول واحد.
بالنسبة لنظام التشغيل Linux ، يحتوي parallel
على وظائف منفصلة: mclapply
، mcmapply
، mcMap
. غالبًا ما يتم تنفيذ الأوامر في نظام التشغيل هذا بشكل أسرع ، ويصبح الرمز أكثر إحكاما.
الرمز 9: حل باستخدام mclapply لنظام التشغيل 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()
عند استخدام هذه الوظائف ، ليست هناك حاجة لبدء نظام المجموعة باستخدام makeCluster
. عدد العقد التي تحددها باستخدام الوسيطة mc.cores . ليست هناك حاجة أيضًا لتوصيل الحزم وتصدير الكائنات ؛ يتم تنفيذ هذه العمليات تلقائيًا.
حزمة future
أحد الأساليب الحديثة في البرمجة غير المتزامنة في برنامج R.
رمز في موازاة ذلك سوف يحل مشكلتنا بمساعدة future
معقدة بما فيه الكفاية لفهم. لذلك ، دعونا نحلل عملها على مثال أبسط ، سنطلب قائمة بالكلمات الرئيسية من حساب واحد.
الرمز 10: أبسط مثال على استخدام الحزمة المستقبلية library(future) # plan(multiprocess) # # future.kw <- future({yadirGetKeyWords(Login = logins[4])}, packages = "ryandexdirect", globals = "logins") # resolved(future.kw) # future.result.1 <- value(future.kw)
دعنا نحاول معرفة مثال الكود 10 . تسمح لك وظيفة plan
بضبط وتغيير وضع تنفيذ التعبيرات المعطاة ، وفيما يلي أهمها:
- تتابعي - هذا هو الوضع العادي للعملية ؛ يتم تنفيذ الأوامر بالتسلسل في الجلسة الحالية ؛
- multisession - الوضع الموازي ، سيتم تنفيذ الأوامر في جلسات التشغيل في الخلفية على الجهاز الحالي ، بينما لن يتم حظر جلسة العمل الخاصة بك ؛
- الكتلة - الوضع الموازي ، سيتم تنفيذ الأوامر على الجهاز الحالي أو البعيد ، على غرار الطريقة التي يتم بها تنفيذها في الحزمة
parallel
.
تعتمد الحزمة future
بالكامل على تنفيذ الأوامر في عمليات الخلفية دون حظر الجلسة الحالية. تشغيل تنفيذ الأوامر يتبع وظيفة نفس الاسم في future
، لذلك عندما نقوم بتشغيل الأمر:
future({yadirGetKeyWords(Login = logins[4])}, packages = "ryandexdirect", globals = "logins")
لا يتم حظر جلستنا الحالية في R ، ويتم تنفيذ الأمر في الخلفية ، وتشغيل جلسة R أخرى.
يمكنك التحقق من الحالة الحالية لعملية تنفيذ تعبير معين باستخدام الوظيفة التي تم resolved
. أخيرًا ، يتم استخدام دالة value
للحصول على نتيجة التنفيذ future
. إذا قمت بتشغيل دالة value
قبل التشغيل future
في جلسة تشغيل موازية ، فسيتم حظر جلسة العمل الحالية حتى يكتمل تعبير الجلسة الموازية.
مثال العمل الأكثر تقدما هو استخدام future
بالتزامن مع promises
.
الكود 11: مثال على مشاركة حزم "المستقبل" و "الوعود" library(future) library(promises) # plan(multiprocess) # # future.kw <- future({suppressMessages( yadirGetKeyWords(Login = logins[4]))}, packages = "ryandexdirect", globals = "logins") %...>% # future, # nrow() %...>% paste("words loaded") %...>% print()
توفر حزمة promises
مجموعة من مشغلي خطوط الأنابيب التي تكمل تمامًا الوظائف future
.
في مثال الكود 11 ، في الخلفية ، نبدأ عملية تنزيل الكلمات الرئيسية من حساب إعلاني واحد. علاوة على ذلك ، ينتظر مشغل خط الأنابيب %...>%
دون حظر جلسة العمل future
، ويقوم بتنفيذ العمليات المتبقية. نتيجة لتنفيذ التعليمات البرمجية ، عند الانتهاء من العمل في future
، سيتم عرض عدد الكلمات الرئيسية من الحساب المحدد في وحدة التحكم:
[1] "1855 words loaded"
في نهاية المقال ، سيتم عرض مثال توضيحي أكثر لمجموعة من future
promises
.
بشكل افتراضي ، تقوم الحزمة future
نفسها بتصدير مساحة العمل بأكملها إلى كل جلسة تشغيل متوازية ، لكن يمكنك أنت بنفسك تحديد قائمة بالكائنات للتصدير باستخدام وسيطة globals .
لتوصيل الحزم future
يجب future
تمرير متجه يحتوي على أسمائهم إلى وسيطة الحزم .
الآن عدنا إلى مهمتنا ، سيقوم مثال التعليمة البرمجية التالي في الوضع المتوازي بتحميل قائمة بالكلمات الرئيسية من 4 حسابات:
الرمز 12: مثال على حل مشكلة باستخدام الحزمة المستقبلية 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)
يؤدي الوقت: 14.83 sec elapsed
لتنزيل قائمة بالكلمات الرئيسية في وضع متعدد الخيوط من جميع حسابات الإعلانات المدرجة في تسجيلات دخول المتجهات ، تحتاج إلى تشغيل future
منفصل في الخلفية. في مثال التعليمة البرمجية 12 ، ننفذ هذا باستخدام وظيفة lapply
.
نتيجة العمل lapply
هي قائمة future
أطلقت. يمكنك التحقق من حالة كل استخدام باستخدام الأمر sapply(futs, resolved)
، والذي سيعيد متجهًا منطقيًا حيث يعني TRUE أن future
تحقق ، وأن FALSE هذا future
قيد التقدم حاليًا.
للحصول على نتائج من كل future
، بعد اكتمال عملهم ، نستخدم الأمر 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 . أي , , 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
:
%...>%
— %>%
, . أي , 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 , .
استنتاج
R, API.
, API . " R , 1" .
:
- doSNOW / doParallel + foreach
- future + promises
- future.apply / furrr
- parallel
, , .
, R .