Когда и как горутина попадает в глобальную очередь планировщика Go?

Ответ

Горутина не перемещается в глобальную очередь при блокировке. Когда горутина блокируется (например, при ожидании канала, мьютекса или завершении системного вызова), она снимается с выполнения на логическом процессоре (P), и её состояние меняется на ожидающее. P становится свободным для выполнения других горутин.

Горутины попадают в глобальную очередь планировщика Go (Global Run Queue) в следующих основных случаях:


  1. При создании новой горутины: Когда вы вызываете go func(), новая горутина обычно добавляется в локальную очередь выполнения текущего логического процессора (P). Если локальная очередь переполнена, горутина помещается в глобальную очередь.



  2. После возврата из блокирующего системного вызова (Syscall): Если горутина завершила длительный блокирующий системный вызов (например, чтение файла или CGO вызов), и логический процессор (P), на котором она выполнялась до блокировки, уже занят другой горутиной, то разблокированная горутина может быть помещена в глобальную очередь, чтобы её мог подобрать любой свободный P.



  3. Явный вызов runtime.Gosched(): Эта функция добровольно уступает текущий логический процессор, делая текущую горутину снова доступной для выполнения. Часто в этом случае горутина помещается в глобальную очередь.



  4. Балансировка нагрузки (Work Stealing): Когда логический процессор (P) исчерпывает горутины в своей локальной очереди, он пытается "украсть" горутины из локальных очередей других P или из глобальной очереди. В этом случае горутины перемещаются из глобальной очереди в локальную очередь P, который их "украл".


Глобальная очередь служит центральным пулом для балансировки нагрузки и как резервное хранилище, когда локальные очереди переполнены или недоступны.