Sobes.tech
Back to questions
Junior — Middle
86

Что такое взаимная блокировка (Deadlock) при использовании горутин и как ее избежать?

Answer from AI

sobes.tech AI

Взаимная блокировка (deadlock) в контексте горутин — это ситуация, когда две или более горутины навсегда блокируют друг друга, ожидая освобождения ресурсов, которые заняты друг другом. Например, если горутина A ждёт ресурс, занятый горутиной B, а горутина B ждёт ресурс, занятый горутиной A, то возникает взаимная блокировка.

В Go это может проявляться при неправильном использовании каналов или мьютексов. Например, если горутина пытается отправить данные в канал, но никто не читает из него, или если несколько горутин пытаются захватить мьютексы в разном порядке.

Как избежать взаимной блокировки:

  • Избегайте циклических зависимостей при захвате нескольких мьютексов — всегда захватывайте их в одном и том же порядке.
  • Используйте буферизированные каналы, чтобы избежать блокировки при отправке, если это уместно.
  • Применяйте таймауты и контексты (context.Context) для отмены операций, если ожидание затягивается.
  • Минимизируйте количество блокирующих операций и старайтесь проектировать архитектуру так, чтобы горутины не зависели друг от друга напрямую.

Пример простой deadlock ситуации с каналами:

ch := make(chan int)

func main() {
    go func() {
        ch <- 1 // блокируется, т.к. никто не читает
    }()
    // main не читает из ch, горутина навсегда заблокирована
}

Чтобы избежать, нужно читать из канала:

ch := make(chan int)

func main() {
    go func() {
        ch <- 1
    }()
    val := <-ch // чтение разблокирует горутину
    fmt.Println(val)
}