Если несколько потоков ждут одну блокировку, чтобы работать с одними и теми же данными, то сколько потоков ни добавляй, выполняется только один за раз.
Почему Несколько потоков одновременно работают с общими данными, например аукционом или хранилищем гильдии → Следствие Пока поток, захвативший блокировку, не закончит, остальные ждут → На экране Тормозит только определённая функция, в тяжёлых случаях отстают тики всего сервера
Основной ответственный Команда разработки · Разработка сервера
Команда разработки: задачи
Дробить блокировки, сокращать работу под блокировкой, перейти на архитектуру на сообщениях (у каждых данных свой поток-владелец, а остальные потоки только отправляют ему запросы сообщениями).
Цифры для ориентира
Если работа под блокировкой занимает 20% задачи, то сколько потоков ни добавляй, производительность вырастет максимум в 5 раз по сравнению с одним потоком, а при 40% остановится на 2,5 раза.
На графике
Растёт вслед за онлайном и нагрузкой · время обработки запросов, CPU и переключения контекста по потокам
Где смотреть
Смотреть добровольные переключения контекста по потокам через pidstat -w -t 1 (cswch/s, сколько раз поток останавливался в ожидании ресурса) и через bcc offcputime -p, где потоки ждут вне CPU (время ожидания по стекам вызовов). Для .NET смотреть число конфликтов блокировок в dotnet-counters (начиная с .NET 9 dotnet.monitor.lock_contentions, в 8 и ниже Monitor Lock Contention Count)
Подтверждает
С ростом нагрузки загрузка CPU остаётся низкой, а время обработки растёт. Большая часть ожидания приходится на стеки вызовов, пытающиеся захватить блокировку, и вместе с этим растёт число конфликтов блокировок
Опровергает
Если CPU загружен полностью, дело в объёме расчётов (превышение бюджета тика, перегрузка однопоточной локации). Если потоки ждут в вызовах БД или файлов, дело в синхронных вызовах в игровом потоке
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Подробнее
Это бывает там, где несколько потоков вместе меняют игровые данные. Если каждую локацию или функцию обслуживает один поток и потоки общаются только сообщениями, блокировок почти нет, зато нужно следить, чтобы работа не скапливалась на одном потоке (перегрузка однопоточной локации). Если игровой поток ждёт блокировку, которую держит медленная операция сохранения, стоит весь тик.
Amdahl's Law in the Multicore EraIEEE Статья в IEEE Computer 2008 (авторская версия). Если доля работы, которую нельзя распараллелить, равна 1−f, то сколько ядер ни добавляй, ускорение не превысит 1/(1−f) (закон Амдала)
Request schedulingMicrosoft Грейны (акторы) Orleans работают по однопоточной модели и обрабатывают запросы по одному до конца, поэтому состояние не меняется одновременно. Если грейны ждут ответа друг от друга, возможен дедлок
pidstat(1) — Linux manual pagesysstat cswch/s в выводе -w: число добровольных переключений контекста, когда поток остановился в ожидании ресурса. -t выводит данные по потокам
Well-known EventCounters in .NETMicrosoft Monitor Lock Contention Count (monitor-lock-contention-count): сколько раз попытка захватить блокировку монитора наткнулась на конкуренцию
.NET runtime metrics.NET Начиная с .NET 9 dotnet.monitor.lock_contentions: сколько раз с запуска процесса попытка захватить блокировку монитора наткнулась на конкуренцию