У Delphi XE7 була включена бібліотека для паралельного програмування. Щоб її використовувати, досить підключити юніт System.Threading. Давайте розберемося, що в цій бібліотеці є і як її можна використовувати.
Бібліотека паралельного програмування Parallel Programming Library (PPL) працює на Windows. MacOSX. Android і iOS пристроях і дозволяє вашим додаткам запускати завдання паралельно, використовуючи тим самим переваги багатопроцесорних девайсів або комп'ютерів. Бібліотека PPL дозволить вам запускати завдання, об'єднувати їх, очікувати виконання групи завдань і багато іншого. Для всього цього в бібліотеці є автоматично настроюється (в залежності від завантаження процесора) пул потоків (див. Клас TThreadPool), який дозволить вам забути про створення і управління потоками.
Використовуючи бібліотеку PPL ви зможете з легкістю:
- створювати цикли, використовуючи конструкцію TParallel.For;
- запускати паралельні завдання, використовуючи TTask і ITask;
- кинути виконується процес, сфокусувавшись на інші завдання, а потім отримати результат цього процесу в точці, в якій ви хочете.
Використання TTask
TTask - це клас, який дозволяє запускати одну задачу або кілька завдань паралельно. При цьому вам не доведеться створювати потік і керувати ним. Клас TTask реалізує інтерфейс ITask. В інтерфейсі ITask в вашому розпорядженні є функції для запуску (Start), очікування (Wait) і скасування (Cancel) завдання і статус (Status), що дозволяє дізнатися, що відбувається з завданням. Ось можливі статуси завдання: Created (завдання створена), WaitingToRun (завдання очікує закінчення виконання іншого процесу), Running (завдання виконується), Completed (завдання завершена), WaitingForChildren (завдання очікує закінчення виконання дочірньої завдання), Canceled (завдання було скасовано), Exception (при виконанні завдання сталася помилка).
Подивимося тепер, як створити і запустити задачу. Для цього потрібно створити клас TTask. передавши в конструктор класу процедуру, яка буде виконуватися в потоці, а потім викликати функцію Start.
А тепер спробуємо виконати кілька завдань паралельно. Для цього потрібно створити масив завдань, запустити завдання і чекати коли вони виконаються. Для очікування є дві статичні функції класу TTask. WaitForAll (очікувати виконання всіх завдань) і WaitForAny (очікувати виконання хоча б одним із завдань).
І наостанок, ще один приклад, в якому я покажу, як звертатися до властивостей і контролю форми з процедури завдання, як перевіряти статус завдання і як скасувати її виконання.
Використання TParallel.For
Статична функція For класу TParallel дозволяє з легкістю виконувати вашу функцію в паралельному циклі. Як приклад розглянемо алгоритм пошуку простих чисел. Функція, що визначає чи є число простим, буде такою:
Класичний масив перебору чисел і підрахунку кількості знайдених простих чисел буде виглядати так:
Зробити паралельний цикл в цьому випадку можна замінивши оператор for на функцію класу TParallel.For і підставивши код циклу в анонімну функцію.
Тепер давайте подивимося, як перервати цикл TParallel.For. Припустимо нам потрібно знайти не менше 1000 простих чисел, а потім перервати цикл. Ось яким стане наш код.
Використання TTask.IFuture
Використовуючи інтерфейс IFuture ви можете порахувати що-небудь або виконати будь-якої запит, паралельно виконуючи інші завдання, і отримати результат в той час, коли вам це буде потрібно. Якщо в цій точці значення ще не буде готове, запитувач потік буде заблокований, поки значення що не отримано. Це дозволяє виставляти пріоритети блокам вашого коду, виконуючи їх в певному порядку, і при цьому бути впевненими, що ви отримаєте значення в певній точці.
Зробимо простий приклад використання інтерфейсу IFuture. Для початку запустимо завдання і спробуємо відразу отримати значення. У наступному прикладі програма переривається, поки не відпрацює завдання.
А ось приклад, коли програма запитує результат після того як завдання вже відпрацювала. В цьому випадку результат буде отримано відразу.
Управління пулом потоків TThreadPool
Отримати поточний екземпляр класу TThreadPool ви можете з властивості класу TThreadPool.Default. у якого ви зможете вважати або у якому можна змінити максимальна і мінімальна кількість потоків. Як це зробити, показано в прикладі.
Чи варто використовувати бібліотеку паралельного програмування Delphi?
Відповідь на це питання однозначна: звичайно варто. Ви зможете збільшити продуктивність існуючих додатків завдяки самоналагоджувальна пулу потоків, який дозволить використовувати переваги багатоядерних процесорів. Крім того, якщо ви використовуєте потоки, то бібліотека паралельного програмування PPL дозволить скоротити розмір коду і поліпшити його читабельність, що не може не радувати. Особливо варто відзначити простоту використання потоків і розпаралелювання циклів.