Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Apakah punca kebuntuan dalam kod Go menggunakan WaitGroups dan Saluran Buffer?

Apakah punca kebuntuan dalam kod Go menggunakan WaitGroups dan Saluran Buffer?

PHPz
PHPzke hadapan
2024-02-09 11:09:30750semak imbas

使用 WaitGroups 和 Buffered Channels 的 Go 代码中出现死锁的原因是什么?

editor php Baicao akan menjawab soalan biasa dalam artikel ini: "Apakah punca kebuntuan dalam kod Go menggunakan WaitGroups dan Saluran Penimbalan?" Walau bagaimanapun, kadangkala anda mungkin menghadapi situasi kebuntuan dalam kod yang menggunakannya. Artikel ini akan menyelidiki punca kebuntuan dan menyediakan penyelesaian untuk membantu pembaca mengelakkan masalah ini. Sama ada anda seorang pemula atau pembangun Go yang berpengalaman, artikel ini akan memberikan anda maklumat yang berharga.

Kandungan soalan

Kumpulan menunggu, saluran penampan dan kebuntuan

Kod saya ini menyebabkan kebuntuan, tetapi saya tidak pasti mengapa. Saya telah mencuba menggunakan mutex di beberapa tempat yang berbeza, menutup saluran di dalam dan di luar rutin pergi yang berasingan, tetapi masih keputusan yang sama.

Saya cuba menghantar data melalui satu saluran (inputchan) dan kemudian membaca data dari saluran lain (outputchan)

package main

import (
    "fmt"
    "sync"
)

func listStuff(wg *sync.WaitGroup, workerID int, inputChan chan int, outputChan chan int) {
    defer wg.Done()

    for i := range inputChan {
        fmt.Println("sending ", i)
        outputChan <- i
    }
}

func List(workers int) ([]int, error) {
    _output := make([]int, 0)

    inputChan := make(chan int, 1000)
    outputChan := make(chan int, 1000)

    var wg sync.WaitGroup
    wg.Add(workers)

    fmt.Printf("+++ Spinning up %v workers\n", workers)
    for i := 0; i < workers; i++ {
        go listStuff(&wg, i, inputChan, outputChan)
    }

    for i := 0; i < 3000; i++ {
        inputChan <- i
    }

    done := make(chan struct{})
    go func() {
        close(done)
        close(inputChan)
        close(outputChan)
        wg.Wait()
    }()

    for o := range outputChan {
        fmt.Println("reading from channel...")
        _output = append(_output, o)
    }

    <-done
    fmt.Printf("+++ output len: %v\n", len(_output))
    return _output, nil
}

func main() {
    List(5)
}

Penyelesaian

Kod dalam fungsi utama adalah berterusan, Pertamacuba tulis nilai 3k ​​ke inputchan inputchan 然后将从 outputchanKemudian

akan membaca nilai dari outputchan kod>. <p> </p>Kod anda disekat pada langkah pertama: <ul> <li> <code>inputchan 之前,outputchan 不会流失任何内容,因此工作人员最终会在第一个 1k 值之后卡在 outputchan <- iBerjaya menghantar nilai 3k kepada
  • inputchan 中消耗资源,main 将在大约 2k 个值之后卡在 inputchan <- iSetelah kakitangan berhenti dari
  • inputchan <- i) 和最终消费者 (for o := range outputchan {Salah satu cara untuk menyelesaikan masalah ini ialah dengan meminta pengeluar (

    ) dijalankan dalam goroutine yang berasingan.

    Anda boleh menyimpan salah seorang pelakon ini dalam goroutine utama dan memutarkan pelakon baharu untuk pelakon lain. Contohnya:

    go func(inputchan chan<- int){
        for i := 0; i < 3000; i++ {
            inputchan <- i
        }
        close(inputchan)
    }(inputchan)
    
    done := make(chan struct{})
    go func() {
        close(done)
        // close(inputchan) // i chose to close inputchan above, don't close it twice
        close(outputchan)
        wg.wait()
    }()
    
    ...
    https://www.php.cn/link/80e4c54699b5b8cf8c67dd496909fceb

    done 的操作顺序很重要;通道 doneoutputchan 只能在 wg.done()Nota tambahan: isyarat sekeliling untuk mengarahkan semua kakitangan menutup apabila selesai

    🎜
    // it is best to close inputChan next to the code that controls
        // when its input is complete.
        close(inputChan)
        // If you had several producers writing to the same channel, you
        // would probably have to add a separate waitgroup to handle closing,
        // much like you did for your workers
    
        go func() {
            wg.Wait()
            // the two following actions must happen *after* workers have
            // completed
            close(done)
            close(outputChan)
        }()

    Atas ialah kandungan terperinci Apakah punca kebuntuan dalam kod Go menggunakan WaitGroups dan Saluran Buffer?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan:
    Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam