Golang Starvation горутин
Starvation (голодание) горутин
Starvation (голодание) горутин в Go возникает, когда одна или несколько горутин не могут получить доступ к ресурсам или выполнить свою работу из-за того, что другие горутины постоянно monopolize (монополизируют) эти ресурсы. Это может привести к тому, что «голодающие» горутины будут indefinitely (бесконечно) ожидать своей очереди на выполнение.
Причины Starvation в Go
- Несправедливое планирование:
- Если одна горутина постоянно занимает процессорное время (CPU time), другие горутины могут не получать шанса на выполнение.
- Например, если горутина выполняет длительный цикл без вызова блокирующих операций (например,
time.Sleep
или каналов), планировщик Go может не переключиться на другие горутины.
- Неправильное использование мьютексов:
- Если горутина долго удерживает мьютекс, другие горутины, ожидающие этот мьютекс, могут «голодать».
- Например:
12345678910111213var mu sync.Mutexgo func() {mu.Lock()// Долгая операцияtime.Sleep(10 * time.Second)mu.Unlock()}()go func() {mu.Lock() // Эта горутина будет ждать 10 секундmu.Unlock()}()
- Несправедливое распределение ресурсов:
- Если несколько горутин конкурируют за общий ресурс (например, канал или пул соединений), некоторые из них могут не получить доступ к ресурсу в течение длительного времени.
- Проблемы с каналами:
- Если горутина отправляет данные в канал, но нет горутин, читающих из него, или наоборот, это может привести к блокировке и голоданию.
Пример Starvation
Рассмотрим пример, где одна горутина monopolize процессорное время, а другие горутины «голодают»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package main import ( "fmt" "runtime" "time" ) func main() { runtime.GOMAXPROCS(1) // Ограничиваем количество потоков до 1 go func() { for { fmt.Println("Горутина 1 работает") } }() go func() { for { fmt.Println("Горутина 2 работает") } }() time.Sleep(1 * time.Second) // Даем время для выполнения } |
В этом примере:
- Мы ограничили количество потоков до 1 с помощью
runtime.GOMAXPROCS(1)
. - Первая горутина monopolize процессорное время, и вторая горутина практически не получает шанса на выполнение.
Как избежать Starvation?
- Используйте
time.Sleep
илиruntime.Gosched()
:- Если горутина выполняет длительные вычисления, добавьте вызов
time.Sleep
илиruntime.Gosched()
, чтобы дать шанс другим горутинам. - Пример:
123456go func() {for {fmt.Println("Горутина 1 работает")runtime.Gosched() // Даем шанс другим горутинам}}()
- Если горутина выполняет длительные вычисления, добавьте вызов
- Справедливое использование мьютексов:
- Не удерживайте мьютекс слишком долго. Если операция требует много времени, разбейте её на части.
- Используйте
sync.RWMutex
, если возможно, чтобы разрешить множественное чтение.
- Используйте каналы и
select
:- Каналы и
select
помогают организовать справедливое распределение работы между горутинами. - Пример:
1234567891011121314151617181920ch := make(chan int)go func() {for {select {case ch <- 1:fmt.Println("Отправлено 1")case ch <- 2:fmt.Println("Отправлено 2")}}}()go func() {for {fmt.Println("Получено:", <-ch)}}()time.Sleep(1 * time.Second)
- Каналы и
- Используйте пулы горутин:
- Если у вас много задач, используйте пул горутин (например, с помощью
sync.WaitGroup
или библиотекиworker pool
), чтобы распределить работу равномерно.
- Если у вас много задач, используйте пул горутин (например, с помощью
- Настройте
GOMAXPROCS
:- Убедитесь, что
GOMAXPROCS
установлено в значение, соответствующее количеству ядер процессора, чтобы горутины могли выполняться параллельно.
- Убедитесь, что
Пример с runtime.Gosched()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package main import ( "fmt" "runtime" "time" ) func main() { runtime.GOMAXPROCS(1) go func() { for { fmt.Println("Горутина 1 работает") runtime.Gosched() // Даем шанс другим горутинам } }() go func() { for { fmt.Println("Горутина 2 работает") runtime.Gosched() // Даем шанс другим горутинам } }() time.Sleep(1 * time.Second) } |
runtime.Gosched()
позволяет планировщику Go переключиться на другую горутину, что предотвращает starvation.
Итог
Starvation горутин — это проблема, которая возникает, когда одна или несколько горутин не могут получить доступ к ресурсам или процессорному времени. Чтобы избежать starvation:
- Используйте
runtime.Gosched()
илиtime.Sleep
для уступки процессорного времени. - Справедливо используйте мьютексы и каналы.
- Настройте
GOMAXPROCS
в соответствии с количеством ядер процессора.
Recommended Posts
Golang map и Swiss Table
16.03.2025