# Асинхронное выполнение задач

Так как DayZ - практически полностью однопоточная игра, выполнение длительной задачи (например, чтение файла, парсинг json-файла и т.п.) приводит к блокировке выполнения всего процесса. На клиенте это выражается в зависании приложения и, при достаточно долгой задаче, выходом с сервера. На сервере это выражается в лагах и отключении игроков от сервера. Для решения данной проблемы в MBSL реализован механизм асинхронного выполнения задач, основная идея которого в разделении задачи на мелкие подзадачи и выполнении их не за раз, а на каждом вызове Update.

_**Важно: система асинхронного выполнения не гарантирует порядка выполнения задач, поэтому задача, которая была добавлена позже, может выполнится раньше.**_

## Класс задачи

Для создания асинхронной задачи необходимо реализовать выполняющий её класс. Базовым классом для таких классов служит MBSL\_AsyncTaskBase, исходный код которого приведён ниже:

```clike
enum MBSL_AsyncTaskStepResult
{
	TaskInProgess,
	TaskWaiting,
	TaskFinished
}

class MBSL_AsyncTaskBase : Managed
{
	MBSL_AsyncTaskStepResult Step(float timeslice);
}
```

Данный класс требует реализации всего одной функции Step, которая принимает один аргумент timeslice - время между предыдущим и предпредыдущим кадром. В этой функции задача должна выполнять одну из своих подзадач, при этом не рекомендуется, чтобы время выполнения превышало 10 мс, иначе теряется смысл асинхронного механизма выполнения.

Функция возвращает одной из значений enum'а MBSL\_AsyncTaskStepResult:

* TaskInProgress - задача выполняла работу на этом вызове Step и ещё не завершила выполнение.
* TaskWaiting - задача не выполняла работу на этом вызове (например, она ждёт чего-то), но ещё не завершила выполнение. **Устаревшее значение, которое более не используется, но оставлено для обратной совместимости.**
* TaskFinished - задача завершила выполнение работы.

## Диспетчер задач

Диспетчер (MBSL\_Dispatcher) - это класс, отвечающий за ведение очереди задач и вызов метода Step на задаче для выполнения. Для его использования требуется всего один метод:

```clike
static void QueueTask(MBSL_AsyncTaskBase task)
```

Данный метод принимает два аргумента:

* task - экземпляр выполняемой задачи.

## Принцип работы диспетчера

Текущая версия диспетчера построена на идее бюджета времени выполнения.

Сервер имеет целевую частоту тиков (TPS - ticks per second) для поддержания стабильной работы. На основе этого значения определяется бюджет времени выполнения для каждого тика (например, при TPS = 60 это значение равно 1/60 = 16 мс). Каждый тик диспетчер определяет уже затраченное игрой время на обработку тика и вычисляется оставшийся бюджет времени.

Диспетчер выдаёт тик максимальному возможному числу задач, не превышая этот бюджет времени. При этом диспетчер ведёт учёт среднего времени тика каждой задачи и использует эту информацию, чтобы определить, умещается ли следующая задача в оставшийся бюджет.
