В каких случаях горутина переходит в состояние ожидания (блокируется)?

Ответ

Горутина переходит в состояние ожидания (блокируется), когда не может продолжить выполнение и ожидает определенного события. Планировщик Go в этот момент переключается на другую готовую к выполнению горутину.

Основные причины блокировки:

  1. Операции с каналами:

    • Чтение из пустого канала: val := <-ch.
    • Запись в заполненный буферизированный или в небуферизированный канал: ch <- val.
  2. Примитивы синхронизации (пакет sync):

    • Захват заблокированного мьютекса: mu.Lock().
    • Ожидание WaitGroup: wg.Wait().
    • Вызов Cond.Wait().

  3. Сетевые и файловые I/O-операции. Большинство системных вызовов, связанных с вводом-выводом, интегрированы с планировщиком Go. Горутина "засыпает" до получения данных из сети или файла.



  4. Таймеры и time.Sleep. Вызов time.Sleep(duration) переводит текущую горутину в режим ожидания на указанное время.



  5. Оператор select. Если ни один из case в select не готов к выполнению и отсутствует ветка default, вся конструкция select блокирует горутину до тех пор, пока одна из операций не станет доступной.



  6. Вызов runtime.Gosched(). Это добровольная уступка процессорного времени. Горутина не блокируется в ожидании события, а просто позволяет планировщику запустить другие горутины, после чего вернется в очередь готовых к выполнению.


Важно понимать, что в большинстве этих случаев блокируется только сама горутина, а не поток операционной системы (OS thread). Планировщик Go эффективно использует потоки, переключая на них другие, не заблокированные горутины.