Ответ
Горутина, выполняющая синхронный системный вызов (например, файловый I/O или сетевой запрос без netpoll), блокируется на время выполнения этого вызова. В этот момент планировщик Go (scheduler) может переключиться на другую горутину в том же потоке (M), пока системный вызов не завершится.
Пример:
file, err := os.Open("example.txt") // Синхронный вызов
if err != nil {
log.Fatal(err)
}
defer file.Close()
Нюансы:
- Если все потоки (M) заблокированы на системных вызовах, планировщик может создать новый поток (до
GOMAXPROCS). - Для сетевых операций Go использует асинхронный ввод-вывод (через
netpoll), поэтому горутины не блокируются. - Долгие синхронные вызовы (например, тяжелые вычисления в CGO) могут "заморозить" планировщик.