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

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

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

Класс задачи

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

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 на задаче для выполнения. Для его использования требуется всего один метод:

static void QueueTask(MBSL_AsyncTaskBase task, MBSL_AsyncTaskPriority priority = MBSL_AsyncTaskPriority.Normal)

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

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

  • priority - приоритет выполняемой задачи.

Значение параметра priority берётся из enum'а MBSL_AsyncTaskPriority:

  • Idle - задачи низшего приоритета. Задачи этого приоритета будут выполнятся в последнюю очередь, и только если диспетчер считает, что в данный момент сервер не перегружен.

  • Low - задачи низкого приоритета. Они будут выполнятся после задач обычного приоритета.

  • Normal - задачи обычного приоритета. Большая часть задач попадает под эту категорию.

  • High - задачи повышенного приоритета. Диспетчер постарается выполнить наибольшее число этих задач, не повлияв при этом на качество игры.

  • Critical - задачи наивысшего приоритета. Данные задачи выполняются максимально быстро, но при этом большое количество задач может привести к проблемам с качеством игры (лагам, провисаниям). Рекомендуется использовать только для по-настоящему важных задач.

Last updated