Модель багатопоточності.
Під час активного Run виконуються операції у потоках середовища виконання та фреймворку. Вашому застосунку не потрібно керувати цими потоками, але йому необхідно підтримувати порядок у власному коді, що відповідає за надсилання, отримання, обробку зворотних викликів і завершення роботи.
Перепис потоків
Для типового запуску Run:
| Потік | Роль | Належить |
|---|---|---|
| GStreamer: потоки для потокового відтворення | Переміщуйте буфери через шляхи, що включають джерело, трансформацію та кінцеву точку. | GStreamer середовище виконання. |
| Потоки диспетчера MLA. | Надсилайте роботи, оформлені відповідно до вимог MLA, і отримуйте підтвердження про їх завершення. | Neat середовище виконання. |
| Потоки диспетчера EV74 / CVU. | Надайте ядра, розроблені стороною CVU, і перевіряйте їх на готовність. | Neat середовище виконання. |
| Офіціанти, які обслуговують столи з одного боку, і працівники, що прибирають столи | Перемістіть зразки вихідних даних у загальнодоступні черги та повідомляйте про помилки, що виникають під час роботи програми (у середовищі виконання). | Neat середовище виконання. |
| Потоки застосунків. | Викличте Graph.build(...), Graph.run(...), Run.push(...), Run.pull(...), Run.stop() або використовуйте функції зворотного виклику. | Ваша заявка. |
Фрагменти графа, вихідні та кінцеві вузли можуть збільшити обсяг роботи в середовищі виконання, але правило залишається незмінним: загальнодоступний Run – це об’єкт, яким керує ваш застосунок.
Де виконується код застосунку.
Код користувача відображається в таких місцях:
- Прямі виклики API:
build(...),run(...),push(...),try_push(...),pull(...),close_input(),stop()іclose()виконуються в основному потоці застосунку, який їх викликає. - Функції обробки подій відкидання:
RunOptions.on_input_dropвиконується під час передачі даних. Зробіть її короткою: підрахуйте та поверніть результат. - Функції зворотного виклику для тензорів:
Graph::set_tensor_callback(...)– це спосіб споживання даних у стилі функцій зворотного виклику в C++. Робіть функції зворотного виклику короткими, оскільки тривала обробка може призвести д о уповільнення роботи середовища виконання. - Спеціальний опис вузла: створення загальнодоступного вузла та формування графа відбуваються під час збірки, у головному потоці застосунку.
Не намагайтеся приховати тривалі обчислення у функціях зворотного виклику. Якщо функція зворотного виклику потребує виконання великого обсягу роботи, передайте дані до власної черги та завершіть її виконання.
Правила блокування.
Розглядайте Graph, Run, Tensor і Sample як об’єкти, що належать одному користувачеві, якщо API не вказує інше.
Підтримуваний формат:
- один із робочих потоків-виробників викликає
push(...)абоtry_push(...); - один із споживчих потоків викликає
pull(...); - інший координаційний потік може викликати
stop()під час завершення роботи.
Ризикована стратегія:
- кілька потоків-виробників намагаються одночасно отримати доступ до одного й того ж
Runбез використання механізму блокування; - кілька споживчих потоків отримують дані з одного й того ж джерела, при цьому відсутні чіткі правила щодо прав доступу;
- функція зворотного виклику знову викликає ту саму функцію
Runі чекає на подальші завдання.
Якщо вам потрібно кілька виробників, перед викликом Run.push(...) забезпечте послідовний доступ. Якщо вам потрібно кілька споживачів, створіть кілька незалежних потоків після того, як один потік отримає дані з Neat.
Вимкнення та скасування.
Використовуйте команду завершення роботи, яка відповідає вашим намірам:
| Намір | Використовуйте |
|---|---|
| Завершіть обробку завдань зі списку очікування після отримання останнього вхідного сигналу. | run.close_input(), потім продовжуйте, доки не припиниться надходження даних або не буде повернуто значення PullStatus::Closed. |
| Зупиніться зараз і розблокуйте завдання, які очікують на виконання. | run.stop() |
| Звільніть ресурси середовища виконання. | run.close(): завершіть виконання або дозвольте об’єкту Run вийти за межі області видимості. |
stop() – це команда скасування. Після скасування, завантаження даних, що відбуваються під час виконання, припиняються, і подальші завантаження мають бути зупинені. Не слід продовжувати завантажувати дані в процес, який завершується.
Форма потоку даних.
Для графіків, які оновлюються в реальному часі або мають високу пропускну здатність і передаються застосунком, почніть із двох потоків застосунку:
- Потік-продюсер зчитує вхідні дані, додає мітки
stream_id/frame_idі викликаєtry_push(...)абоpush(...)відповідно до обраної політики обробки переповненняOverflowPolicy. - Споживацький потік бе зперервно зчитує дані та звільняє або копіює результати, перш ніж вони будуть закріплені в буферах, що підтримуються середовищем виконання.
Додайте більше робочих потоків для обробки власних черг, а не для одного й того ж об’єкта Run. Зробіть основний цикл обробки менш інтенсивним. Неінтенсивна робота – це швидко.
Для подальшого ознайомлення
- Запустіть граф. — життєвий цикл у середовищі виконання, пропускна здатність, вимірювання та механізм регулювання навантаження.
Run— загальнодоступний об’єкт середовища виконання.- Асинхронна та синхронна моделі часу — коли виконуються завдання та коли відбуваються зворотні виклики.