Многопоточность в браузере

9 April
Многопоточность в браузере на примере игры в шашки
Многопоточность в браузере на примере игры в шашки
Многопоточность в браузере на примере игры в шашки

На странице браузера скрипты выполняются в едином потоке с пользовательским интерфейсом. При объемных вычисления это приводит к «зависанию» - страница перестает реагировать на ввод. Да и сам браузер, замечая такую ситуацию, предлагает ее закрыть.

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

Задачу вычислений в браузере в отдельном потоке решает Web Worker. Он запускается в собственном глобальном контексте и взаимодействует с основным потоком через сообщения.

Продемонстрирую этот функционал на примере игры в шашки на платформе E-Champ с открытым исходным кодом.

Как серверная, так и клиентская части E-Champ написаны на JavaScript и используют свободное окружение (Node.js, MongoDB). Игры и боты подключаются к платформе как отдельные npm модули.

Компьютерный соперник получает список допустимых ходов и должен выбрать один из них. Для анализа вариантов используется алгоритм минимакса, в котором объем вычислений зависит от глубины просчета позиции. Каждый ход оценивается независимо, что позволяет проводить расчет одновременно для всех.

В методе createWorkers для каждого возможного хода создается объект
DraughtsThinkerSolverWorker. Этот класс оборачивает стандартный класс Worker, обеспечивая его адаптацию к игре.

Создание web workers
Создание web workers
Создание web workers

В конструкторе добавляется слушатель окончания работы worker. В методе start отправляется сообщение для worker, что пора приступать к работе.

Запуск web worker через отправку сообщения
Запуск web worker через отправку сообщения
Запуск web worker через отправку сообщения
Сам скрипт worker размещается в отдельном файле. При создании необходимо передать ему абсолютный путь до скрипта.

В глобальном пространстве worker добавляется слушатель основного потока. Как только приходит сообщение, то создается экземпляр решателя и начинается оценка заданного хода.

Подключение обработчика сообщений в собственном пространстве web worker
Подключение обработчика сообщений в собственном пространстве web worker
Подключение обработчика сообщений в собственном пространстве web worker

По окончанию в основной поток отправляется полученное значение. При получении сообщения от worker основной поток проверяет закончена ли обработка других workers. Если все закончены, то выбирается ход с наилучшим значением.

Итак, сейчас при анализе задействуются все ресурсы компьютера.
Особенно легко это заметить, выбирая максимальный уровень сложности соперника. При его ходе нагрузка распределяется на все ядра процессора.

Живая демонстрация игры в шашки в браузере.

Каждый возможный ход анализируется в отдельном потоке
Каждый возможный ход анализируется в отдельном потоке
Каждый возможный ход анализируется в отдельном потоке

P.S. В текущей версии максимальный уровень бота делает просчет на 9 - 10 полуходов. На мощном компьютере задержка при таких вычислениях будет не заметнее первого уровня. Но вы может самостоятельно задать любую глубину просчета, настроив и запустив собственный сервер .