Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Потокобезпечні API

Потоки

Потоки використовуються для балансування потужності процесорів і ядер. Godot підтримує багатопотоковість, але не в усьому двигуні.

Нижче наведено список способів використання багатопоточності в різних областях Godot.

Глобальна область

Більшість одиночних об'єктів Global Scope є потокобезпечними за замовчуванням. Доступ до серверів з потоків підтримується. Однак для серверів rendering та physics потокобезпечну роботу необхідно спочатку ввімкнути в налаштуваннях проекту.

Це робить синглтони ідеальними для коду, який створює десятки тисяч екземплярів на серверах та керує ними з потоків. Звичайно, це вимагає трохи більше коду, оскільки він використовується безпосередньо, а не всередині дерева сцен.

Дерево сцени

Взаємодія з активним деревом сцени не є потокобезпечною. Обов'язково використовуйте м'ютекси під час надсилання даних між потоками. Якщо ви хочете викликати функції або встановлювати властивості з потоку, ви можете використовувати call_deferred або set_deferred:

# Unsafe:
node.add_child(child_node)
# Safe:
node.add_child.call_deferred(child_node)

Однак створення блоків сцени (вузлів у структурі дерева) поза активним деревом є нормальним. Таким чином, частини сцени можуть бути створені або створені в потоці, а потім додані в головному потоці:

var enemy_scene = load("res://enemy_scene.scn")
var enemy = enemy_scene.instantiate()
enemy.add_child(weapon) # Set a weapon.
world.add_child.call_deferred(enemy)

Однак, це справді корисно лише за наявності одного потоку завантаження даних. Спроба завантажити або створити фрагменти сцени з кількох потоків може спрацювати, але ви ризикуєте тим, що ресурси (які завантажуються лише один раз у Godot) будуть змінені кількома потоками, що призведе до неочікуваної поведінки або збоїв.

Використовуйте більше ніж один потік для генерації даних сцени, лише якщо ви справді знаєте, що робите, і ви впевнені, що один ресурс не використовується або встановлений у кількох. В іншому випадку вам безпечніше просто використовувати API серверів (який є повністю потоково-безпечним) безпосередньо і не торкатися сцени чи ресурсів.

Рендеринг

Створення екземплярів вузлів, які рендерять щось у 2D або 3D (наприклад, class_Sprite2D або MeshInstance3D), не є потокобезпечним за замовчуванням. Щоб запустити драйвер рендерингу в окремому потоці, встановіть для налаштування проекту Rendering > Driver > Thread Model значення Separate.

Зверніть увагу, що модель Окремих потоків має кілька відомих помилок, тому вона може бути недоступною в усіх сценаріях.

Попередження

Вам слід уникати виклику функцій, що передбачають пряму взаємодію з графічним процесором в інших потоках, таких як створення нових текстур або зміна та отримання даних зображень. Ці операції можуть призвести до зупинки продуктивності, оскільки вони вимагають синхронізації з RenderingServer, оскільки дані необхідно передавати або оновлювати на графічному процесорі.

Фізика

Фізичне моделювання не є потокобезпечним за замовчуванням. Щоб запускати фізичні сервери в окремих потоках (щоб зробити їх потокобезпечними), увімкніть такі налаштування проекту:

  • PhysicsServer2D: Фізика > 2D > Запуск в окремому потоці.

  • PhysicsServer3D: Фізика > 3D > Запуск в окремому потоці.

Масиви та словники GDScript

У GDScript читання та запис елементів з кількох потоків є прийнятним, але будь-що, що змінює розмір контейнера (зміна розміру, додавання або видалення елементів), вимагає блокування. mutex.

Ресурси

Зміна унікального ресурсу з кількох потоків не підтримується. Однак обробка посилань у кількох потоках підтримується. Отже, завантаження ресурсів у потік також підтримується — сцени, текстури, сітки тощо — можна завантажувати та маніпулювати ними в потоці, а потім додавати до активної сцени в головному потоці. Обмеження тут описане вище: потрібно бути обережним, щоб не завантажувати один і той самий ресурс з кількох потоків одночасно. Тому найпростіше використовувати один потік для завантаження та зміни ресурсів, а потім головний потік для їх додавання.