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

PHPz
Lepaskan: 2024-02-09 11:09:30
ke hadapan
722 orang telah melayarinya

使用 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)
}
Salin selepas log masuk

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()
    }()
    
    ...
    Salin selepas log masuk
    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)
        }()
    Salin selepas log masuk

    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!

    Label berkaitan:
    sumber:stackoverflow.com
    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
    Tutorial Popular
    Lagi>
    Muat turun terkini
    Lagi>
    kesan web
    Kod sumber laman web
    Bahan laman web
    Templat hujung hadapan
    Tentang kita Penafian Sitemap
    Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!