Sobes.tech
Junior

Goroutine менен иштөөдө deadlock эмне?

sobes.tech AI

AIден жооп

Deadlock (талаа) — бул эки же көп горутиналар бири-бирин күтүп, блоктоло турган абал. Адатта, бул mutexтер же каналдар менен иштөөдө пайда болот.

Deadlock мисалдары:

  1. Mutexтерди ар башка тартипте блоктоо:

    // Deadlock мисалы mutexтер менен
    var mu1 sync.Mutex
    var mu2 sync.Mutex
    
    func goroutine1() {
        mu1.Lock() // mu1ти алат
        time.Sleep(100 * time.Millisecond) // Кыска күтөт
        mu2.Lock() // mu2ти алууга аракет кылат (ал goroutine2 тарабынан кармалган)
        fmt.Println("goroutine1 mu2ти алды")
        mu2.Unlock()
        mu1.Unlock()
    }
    
    func goroutine2() {
        mu2.Lock() // mu2ти алат
        time.Sleep(100 * time.Millisecond) // Кыска күтөт
        mu1.Lock() // mu1ти алууга аракет кылат (ал goroutine1 тарабынан кармалган)
        fmt.Println("goroutine2 mu1ти алды")
        mu1.Unlock()
        mu2.Unlock()
    }
    

    Goroutine1 mu1ти алды жана mu2ти күтүп жатат. Goroutine2 mu2ти алды жана mu1ти күтүп жатат. Эки goroutine да блоктогон.

  2. Набор в небуферизованный канал без получателя:

    // Deadlock мисалы канал менен
    func main() {
        ch := make(chan int)
        //go func() { // Эгер окуу үчүн goroutine ишке киргизилбесе, deadlock болот
        //	<-ch
        //}()
        ch <- 1 // Каналга жөнөтүү, ал активдүү кабыл алгычсыз
        fmt.Println("Жөнөтүлдү каналга") // Бул сап жеткирилбейт
    }
    

    Небуферизованный каналга жөнөтүү блоктолот, башка goroutine аны окуй баштаганга чейин. Эгер кабыл алгыч жок болсо, deadlock болот.

  3. Каналдан окуу кабыл алгычсыз (жабуу же бош буфер):

    // Deadlock мисалы каналдан окуу
    func main() {
        ch := make(chan int, 1) // Бош буфердүү канал 1 элементке
        ch <- 1 // 1 жөнөтүлдү
        close(ch) // Канал жабылды
        <-ch // 1 окулду
        <-ch // Экинчи жолу окууга аракет - deadlock
    }
    

    Жабылган, бош каналдан окуу ийгиликтүү болот. Жабылган жана бош же ачылган, бирок бош небуферизованный каналдан окуу блокко алып келет.

Golang-дун рунтаймы белгилүү түрлөрүн аныктай алат (мисалы, бардык блоктогон goroutine-лер бир гана goroutine-дин кабыл алуу же жөнөтүү күтүп жатса), жана мындай учурда программа күтүүсүздөн "fatal error: all goroutines are asleep - deadlock!" деген билдирүү менен аяктайт. Бирок, бардык deadlock-лор автоматтык түрдө аныктала бербейт.

Deadlock-лорду алдын алуу үчүн маанилүү:

  • mutexтерди бирдиктүү тартипте алуу;
  • ар бир небуферизованный каналга жөнөтүү үчүн тиешелүү окуу бар экенине көз жеткізүү;
  • каналдар менен иштөөдө select жана default бөлүмдөрүн колдонуу;
  • goroutine-лердин жашоо циклин жана каналдарды жабууну так башкаруу.