WorkerThreadPool
Наследует: Object
Синглтон, который выделяет некоторые Thread при запуске, используемый для разгрузки задач в эти потоки.
Описание
Синглтон WorkerThreadPool выделяет набор Thread (называемых рабочими потоками) при запуске проекта и предоставляет методы для выгрузки задач в них. Это можно использовать для простой многопоточности без необходимости создания Thread.
Задачи содержат Callable для запуска потоками. WorkerThreadPool можно использовать для создания обычных задач, которые будут приниматься одним рабочим потоком, или групповых задач, которые могут быть распределены между несколькими рабочими потоками. Групповые задачи выполняют Callable несколько раз, что делает их полезными для итерации по множеству элементов, таких как враги на арене.
Вот пример того, как выгрузить дорогостоящую функцию в рабочие потоки:
var enemies = [] # Массив, который нужно заполнить врагами.
func process_enemy_ai(enemy_index):
var processed_enemy = enemies[enemy_index]
# Дорогая логика...
func _process(delta):
var task_id = WorkerThreadPool.add_group_task(process_enemy_ai, enemies.size())
# Другой код...
WorkerThreadPool.wait_for_group_task_completion(task_id)
# Другой код, зависящий от уже обрабатываемого ИИ врага.
private List<Node> _enemies = new List<Node>(); // Массив, который нужно заполнить врагами.
private void ProcessEnemyAI(int enemyIndex)
{
Node processedEnemy = _enemies[enemyIndex];
// Дорогая логика...
}
public override void _Process(double delta)
{
long taskId = WorkerThreadPool.AddGroupTask(Callable.From<int>(ProcessEnemyAI), _enemies.Count);
// Другой код...
WorkerThreadPool.WaitForGroupTaskCompletion(taskId);
// Другой код, зависящий от уже обрабатываемого ИИ врага.
}
Приведенный выше код полагается на то, что количество элементов в массиве enemies остается постоянным во время многопоточной части.
Примечание: Использование этого синглтона может отрицательно повлиять на производительность, если задача, распределяемая между потоками, не является вычислительно затратной.
Обучающие материалы
Методы
add_group_task(action: Callable, elements: int, tasks_needed: int = -1, high_priority: bool = false, description: String = "") |
|
add_task(action: Callable, high_priority: bool = false, description: String = "") |
|
get_caller_group_id() const |
|
get_caller_task_id() const |
|
get_group_processed_element_count(group_id: int) const |
|
is_group_task_completed(group_id: int) const |
|
is_task_completed(task_id: int) const |
|
void |
wait_for_group_task_completion(group_id: int) |
wait_for_task_completion(task_id: int) |
Описания метода
int add_group_task(action: Callable, elements: int, tasks_needed: int = -1, high_priority: bool = false, description: String = "") 🔗
Добавляет action в качестве групповой задачи для выполнения рабочими потоками. Callable будет вызываться несколько раз на основе elements, при этом первый поток вызывает его со значением 0 в качестве параметра, а каждое последующее выполнение увеличивает это значение на 1, пока не достигнет element - 1.
Количество потоков, на которые распределяется задача, определяется tasks_needed, где значение по умолчанию -1 означает, что она распределяется на все рабочие потоки. high_priority определяет, имеет ли задача высокий или низкий приоритет (по умолчанию). Вы можете дополнительно указать description для помощи в отладке.
Возвращает идентификатор групповой задачи, который может использоваться другими методами.
Предупреждение: В какой-то момент необходимо дождаться завершения каждой задачи с помощью wait_for_task_completion() или wait_for_group_task_completion(), чтобы можно было освободить все выделенные внутри задачи ресурсы.
int add_task(action: Callable, high_priority: bool = false, description: String = "") 🔗
Добавляет action в качестве задачи для выполнения рабочим потоком. high_priority определяет, имеет ли задача высокий или низкий приоритет (по умолчанию). При желании вы можете указать description для помощи в отладке.
Возвращает идентификатор задачи, который может использоваться другими методами.
Предупреждение: Каждая задача должна быть дожидаться завершения с помощью wait_for_task_completion() или wait_for_group_task_completion() в какой-то момент, чтобы можно было очистить любые выделенные ресурсы внутри задачи.
int get_caller_group_id() const 🔗
Возвращает ID идентификатор группы задач текущего потока, вызывающего этот метод, или -1, если недопустимо или текущий поток не является частью группы задач.
int get_caller_task_id() const 🔗
Возвращает ID идентификатор задачи текущего потока, вызывающего этот метод, или -1, если задача является групповой задачей, недопустимой или текущий поток не является частью пула потоков (например, основного потока).
Может использоваться задачей для получения собственного идентификатора задачи или для определения того, выполняется ли текущий код внутри пула рабочих потоков.
Примечание: Групповые задачи имеют собственные ID идентификаторы, поэтому этот метод вернет -1 для групповых задач.
int get_group_processed_element_count(group_id: int) const 🔗
Возвращает, сколько раз Callable групповой задачи с указанным идентификатором уже был выполнен рабочими потоками.
Примечание: Если поток начал выполнение Callable, но еще не завершил его, он не будет засчитан.
bool is_group_task_completed(group_id: int) const 🔗
Возвращает true, если групповая задача с указанным идентификатором завершена.
Примечание: Вызвать этот метод следует только между добавлением групповой задачи и ожиданием ее завершения.
bool is_task_completed(task_id: int) const 🔗
Возвращает true, если задача с указанным идентификатором завершена.
Примечание: Вызвать этот метод следует только между добавлением задачи и ожиданием ее завершения.
void wait_for_group_task_completion(group_id: int) 🔗
Приостанавливает поток, вызывающий этот метод, до тех пор, пока не будет завершена групповая задача с указанным идентификатором.
Error wait_for_task_completion(task_id: int) 🔗
Приостанавливает поток, вызывающий этот метод, до тех пор, пока задача с указанным идентификатором не будет завершена.
Возвращает @GlobalScope.OK, если задача может быть успешно ожидана.
Возвращает @GlobalScope.ERR_INVALID_PARAMETER, если задача с переданным идентификатором не существует (возможно, потому что она уже была ожидаема и удалена).
Возвращает @GlobalScope.ERR_BUSY, если вызов выполняется из другой запущенной задачи и из-за планирования задач существует вероятность взаимоблокировки (например, задача для ожидания может находиться на более низком уровне в стеке вызовов и, следовательно, не может выполняться). Это сложная ситуация, которая должна иметь значение только тогда, когда некоторые задачи зависят от других (в текущей реализации сложный случай — это задача, пытающаяся ждать более старую).