Модель багатопоточності.
Під час активного 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.