Виды нагрузок
Как узнать, когда выполнение вне очереди возможно или имеет смысл? Начни с определения типа рабочей нагрузки, с которой справляется твоя проблема. Есть два типа рабочих нагрузок, которые важно понимать, когда речь идет о конкурентной модели.
-
CPU-Bound: это рабочая нагрузка, которая никогда не создает ситуации, где горутины естественным образом входят в состояние ожидания и выходят из него. Это работа, которая заключается в постоянном выполнении расчетов. Поток, вычисляющий Pi до N-й цифры, будет привязан к процессору.
-
IO-Bound: это рабочая нагрузка, которая заставляет горутины естественным образом переходить в состояние ожидания. Это работа, которая заключается в запросе доступа к ресурсу по сети или выполнении системных вызовов в операционную систему, или ожидании наступления события. Горутина, которой нужно прочитать файл, будет привязана к IO. В эту категорию также стоит включить события синхронизации (мьютексы, атомарные), которые заставляют Горутин ждать.
При рабочих нагрузках, привязанных к процессору, тебе нужен параллелизм, чтобы использовать конкурентность. Один поток ОС/аппаратного обеспечения, обрабатывающий несколько горутин, неэффективен, поскольку горутины не входят в состояние ожидания и не выходят из него в рамках своей рабочей нагрузки. Если горутин больше, чем потоков ОС/аппаратных средств, это может замедлить выполнение рабочей нагрузки из-за затрат на задержку (время, которое требуется) для перемещения горутин в поток ОС и из него. Переключение контекста создает событие «Остановить мир» (Stop The World) для твоей рабочей нагрузки, поскольку ни одна из рабочих нагрузок не выполняется во время переключения, хотя в противном случае это могло бы быть.
С рабочими нагрузками, связанными с вводом-выводом, тебе не нужен параллелизм для использования конкурентной модели. Один поток ОС/аппаратного обеспечения может эффективно обрабатывать несколько горутин, поскольку горутины естественным образом входят в состояние ожидания и выходят из него в рамках своей рабочей нагрузки. Если горутин больше, чем потоков ОС/аппаратных средств, это может ускорить выполнение рабочей нагрузки, поскольку стоимость задержки перемещения горутин в поток ОС и из него не приводит к возникновению события «Stop The World». Рабочая нагрузка естественным образом останавливается, и это позволяет другой Goroutine эффективно использовать один и тот же поток ОС/аппаратного обеспечения вместо того, чтобы позволить потоку ОС/аппаратного обеспечения бездействовать.
Как узнать, сколько горутин на аппаратный поток обеспечивает наилучшую пропускную способность? Слишком мало Горутин означает, что у тебя больше времени простоя. Слишком много Горутин увеличивают время ожидания переключения контекста. Об этом нужно подумать.
Сейчас важно просмотреть код, чтобы укрепить твою способность определять, когда рабочая нагрузка может использовать параллелизм, а когда нет, и нужна ли тебе конкурентность.
Подробнее о событии «__Stop the world__» ты можешь узнать по ссылке.