پیش از C++17، الگوریتم‌های کتابخانه‌ی استاندارد (STL) همگی به‌صورت ترتیبی و تک‌ریسه‌ای اجرا می‌شدند. C++17 با معرفی سیاست‌های اجرایی موازی، این رویه را دگرگون کرده است. کار به‌قدری ساده است که می‌توان با تغییر تنها یک پارامتر، از مزایای پردازش چند هسته‌ای بهره‌مند شد. به‌عنوان نمونه، فراخوانی سنتی تابع std::sort به صورت std::sort(vec.begin(), vec.end())، با اضافه کردن یک پارامتر به std::sort(std::execution::par, vec.begin(), vec.end()) تغییر می‌کند و الگوریتم مرتب‌سازی به‌صورت موازی اجرا می‌شود . این قابلیت که نیازمند درج هدر <execution> است، استفاده از توان پردازنده‌های چند هسته‌ای را برای برنامه‌نویسان به شدت ساده می‌کند و نیازی به مدیریت مستقیم ریسه‌ها یا استفاده از کتابخانه‌های سطح پایین ندارد .

سیاست‌های اجرایی: seq، par، par_unseq و unseq

C++17 سه سیاست اجرایی اصلی را در فضای نام std::execution تعریف کرده است که هر یک سطح مشخصی از موازی‌سازی و برداری‌سازی را مجاز می‌دانند . سیاست std::execution::seq یک سیاست ترتیبی است که الگوریتم را به‌صورت دنباله‌ای و در همان ریسه‌ی فراخواننده اجرا می‌کند و برای مجموعه‌داده‌های کوچک یا عملیات‌های ساده که سربار موازی‌سازی از مزایای آن بیشتر است، انتخاب مناسبی محسوب می‌شود . سیاست std::execution::par یک سیاست موازی است که به کتابخانه اجازه می‌دهد تا الگوریتم را با استفاده از چندین ریسه به‌صورت همزمان اجرا کند و برای مجموعه‌داده‌های بزرگ و عملیات‌های سنگین محاسباتی مانند std::sort، std::find و std::transform بسیار کارآمد است . سیاست std::execution::par_unseq یک سیاست موازی و بردارگونه است که علاوه بر اجرای موازی با چندین ریسه، به کتابخانه اجازه می‌دهد تا از دستورات برداری (SIMD) نیز برای افزایش سرعت استفاده کند و برای عملیات‌های کاملاً مستقل که ترتیب اجرا در آنها اهمیت ندارد، بهترین گزینه است .

کدام الگوریتم‌ها قابلیت موازی‌سازی دارند؟

تعداد قابل‌توجهی از الگوریتم‌های موجود در کتابخانه‌ی استاندارد، نسخه‌ی موازی خود را در C++17 دریافت کرده‌اند. این الگوریتم‌ها که شامل عملیات‌های پرکاربردی مانند std::sort، std::find، std::transform، std::copy، std::count، std::replace، std::remove و بسیاری دیگر هستند، اکنون می‌توانند با اضافه کردن یک پارامتر سیاست اجرایی، به‌صورت موازی یا بردارگونه اجرا شوند .

ملاحظات مهم در استفاده از سیاست‌های موازی

با وجود سهولت استفاده، استفاده از سیاست‌های par و par_unseq مسئولیت‌های مهمی را بر عهده‌ی برنامه‌نویس می‌گذارد. جلوگیری از رخدادهای رقابتی (Data Races) و بن‌بست‌ها (Deadlocks) کاملاً بر عهده‌ی برنامه‌نویس است و کتابخانه هیچ تضمینی در این زمینه ارائه نمی‌دهد . به‌عنوان مثال، افزودن عناصر به یک std::vector مشترک از درون یک حلقه‌ی موازی، یک رخداد رقابتی است که می‌تواند به خرابی برنامه منجر شود. همچنین در صورت پرتاب شدن یک استثنا از درون تابع فراخوانی‌شده در الگوریتم با هر یک از این سیاست‌ها، std::terminate فراخوانی خواهد شد . نکته‌ی مهم دیگر این است که موازی‌سازی یک داروی جادویی نیست و همیشه منجر به افزایش سرعت نمی‌شود . سربار ایجاد و مدیریت ریسه‌ها می‌تواند برای مجموعه‌داده‌های کوچک یا عملیات‌های بسیار ساده، از هرگونه مزیت عملکردی بیشتر باشد و در برخی موارد، اجرای موازی حتی می‌تواند کندتر از اجرای ترتیبی باشد

کلیدواژه ها : الگوریتم‌های موازی C++17-اعمال سیاست اجرایی در STL-std::execution::par-std::execution::par_unseq-std::execution::seq-هدر execution در C++17-موازی‌سازی std::sort-استفاده از std::transform موازی-فهرست الگوریتم‌های موازی C++17-پرفورمنس الگوریتم‌های موازی-مسئولیت برنامه‌نویس در موازی‌سازی-مدیریت ریسه در C++17-مزایا و معایب موازی‌سازی-نمونه کد موازی STL-آموزش سیاست‌های اجرایی C++17-موازی‌سازی در STL C++17-