|
Misol. Xaritalash va parallellikni kamaytirishni amalga oshiring
|
bet | 8/13 | Sana | 25.05.2024 | Hajmi | 143,49 Kb. | | #253828 |
Bog'liq 1-amaliy ish
Moslik operatsiyasi ketma-ketlikdagi har bir qiymatga funktsiyani qo'llaydi. Kamaytirish operatsiyasi ketma-ketlik elementlarini bitta qiymatga birlashtiradi. Xaritani bajarish va operatsiyalarni qisqartirish uchun C++ standart kutubxonasidan std::transform va std::accumulate funksiyalaridan foydalanishingiz mumkin . parallel_transformBiroq, ko'pgina muammolar uchun siz xarita operatsiyasini parallel ravishda bajarish uchun algoritmdan va parallel_reduceparallel ravishda kamaytirish operatsiyasini bajarish uchun algoritmdan foydalanishingiz mumkin.
Quyidagi misolda tub sonlar yig‘indisini ketma-ket va parallel hisoblash uchun zarur bo‘lgan vaqt solishtiriladi. Moslash bosqichida kompozit raqamlar 0 ga aylantiriladi va qisqartirish bosqichida qiymatlar yig'iladi.
C++Nusxalash
// parallel-map-reduce-sum-of-primes.cpp
// compile with: /EHsc
#include
#include
#include
#include
#include
using namespace concurrency;
using namespace std;
// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// Determines whether the input value is prime.
bool is_prime(int n)
{
if (n < 2)
return false;
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
return false;
}
return true;
}
int wmain()
{
// Create an array object that contains 200000 integers.
array a;
// Initialize the array such that a[i] == i.
iota(begin(a), end(a), 0);
int prime_sum;
__int64 elapsed;
// Compute the sum of the numbers in the array that are prime.
elapsed = time_call([&] {
transform(begin(a), end(a), begin(a), [](int i) {
return is_prime(i) ? i : 0;
});
prime_sum = accumulate(begin(a), end(a), 0);
});
wcout << prime_sum << endl;
wcout << L"serial time: " << elapsed << L" ms" << endl << endl;
// Now perform the same task in parallel.
elapsed = time_call([&] {
parallel_transform(begin(a), end(a), begin(a), [](int i) {
return is_prime(i) ? i : 0;
});
prime_sum = parallel_reduce(begin(a), end(a), 0);
});
wcout << prime_sum << endl;
wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;
}
/* Sample output:
1709600813
serial time: 7406 ms
1709600813
parallel time: 1969 ms
*/
Xaritani parallel ravishda bajaradigan va operatsiyani qisqartiruvchi boshqa misol uchun qarang :
Xaritani parallel ravishda bajarish va operatsiyani qisqartirish .
Bo'limlar bilan ishlash
Ma'lumotlar manbaidagi operatsiyani parallellashtirish uchun siz manbani bir vaqtning o'zida bir nechta oqimlar orqali kirish mumkin bo'lgan bir nechta bo'limlarga bo'lishingiz kerak. Ajratuvchi parallel algoritm diapazonlarni iplar o'rtasida qanday ajratish kerakligini aniqlaydi. Ushbu hujjatda avval aytib o'tilganidek, PPL dastlabki ish yukini yaratadigan standart bo'linish mexanizmidan foydalanadi va keyin yuk muvozanatsiz bo'lganda ushbu bo'limlarning yukini taqsimlash uchun yukni uzatish va diapazonni uzatish algoritmidan foydalanadi. Masalan, tsiklning bir iteratsiyasi bir qator takroriy takrorlashlarni tugatsa, ish vaqti boshqa ish zarrachalaridan yukni shu ipga qayta taqsimlaydi. Biroq, ba'zi stsenariylarda siz maxsus dasturingizga mos keladigan boshqa bo'lim mexanizmini belgilashingiz kerak bo'lishi mumkin.
parallel_for, parallel_for_eachva parallel_transformqo'shimcha parametrni oladigan haddan tashqari yuklangan versiyalarni taqdim eting _Partitioner. Ushbu parametr ishni ajratuvchi ajratuvchi turini belgilaydi. Quyida PPL belgilaydigan ajratuvchilar turlari keltirilgan.
concurrency::affinity_partitioner
Yukni belgilangan diapazonlar soniga ajratadi (odatda, tsiklda ishlash uchun mavjud ishchi iplar soni). Ushbu turdagi ajratuvchi ga o'xshaydi static_partitioner, lekin diapazonlarni ishchi iplar bilan taqqoslash orqali kesh o'xshashligini oshiradi. Agar siz bir xil ma'lumotlar to'plamini bir necha marta aylantirsangiz (masalan, sikl ichidagi sikl) va ma'lumotlar keshlangan bo'lsa, ushbu turdagi ajratuvchi ishlashni yaxshilashi mumkin. Bu ajratuvchi bekor qilishda toʻliq ishtirok etmaydi. Bundan tashqari, izchil qulflash semantikasidan foydalanmaydi va shuning uchun to'g'ridan-to'g'ri bog'liqlikka ega bo'lgan parallel halqalar bilan ishlatib bo'lmaydi.
concurrency::auto_partitioner
Yukni dastlabki diapazonlar soniga ajratadi (odatda tsiklda ishlash uchun mavjud ishchi iplar soni). Parametrni oladigan haddan tashqari yuklangan parallel algoritm chaqirilmasa, ish vaqti sukut bo'yicha ushbu turdan foydalanadi _Partitioner. Har bir diapazonni pastki bandlarga bo'lish mumkin, bu esa yukning taqsimlanishini ta'minlaydi. Bir qator ishlar tugagach, ish vaqti ishning pastki diapazonlarini boshqa ish zarrachalaridan shu ipga qayta taqsimlaydi. Agar ish yuki boshqa toifalarga kirmasa yoki bekor qilish yoki birgalikda blokirovka qilish uchun toʻliq yordam kerak boʻlsa, ushbu ajratgichdan foydalaning.
concurrency::simple_partitioner
Yukni shunday diapazonlarga ajratadiki, har bir diapazonda berilgan blok oʻlchami bilan aniqlangan kamida takrorlashlar sonini oʻz ichiga oladi. Ushbu turdagi separator yuk taqsimlashda ishtirok etadi; ammo, ish vaqti diapazonlarni pastki diapazonlarga ajratmaydi. Har bir ishchi ish zarrachasi uchun ish vaqti bekor qilish so'rovini tekshiradi va parametr tomonidan belgilangan takrorlashlar sonini tugatgandan so'ng yukni muvozanatlashni amalga oshiradi _Chunk_size.
Yukni belgilangan miqdordagi diapazonlar bo'ylab taqsimlaydi (odatda tsiklda ishlash uchun mavjud ishchi iplar soni). Ushbu splitter ish faoliyatini yaxshilashi mumkin, chunki u yuk uzatishni ishlatmaydi va shuning uchun kamroq yon yukni o'z ichiga oladi. Parallel halqaning har bir iteratsiyasi qat'iy va teng miqdordagi ishni bajarsa va bekor qilish yoki to'g'ridan-to'g'ri umumiy qulflashni qo'llab-quvvatlashga hojat yo'q bo'lganda foydalaning.
|
| |