Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cara selamat untuk menamatkan goroutine gelung tak terhingga?

Cara selamat untuk menamatkan goroutine gelung tak terhingga?

WBOY
WBOYke hadapan
2024-02-06 09:09:04967semak imbas

终止无限循环 goroutine 的安全方法?

Kandungan soalan

Saya mempunyai goroutine yang bertindak sebagai pendengar. Strim input masuk ke dalam beberapa buffer channel,我希望我的 goroutine 处理传入该通道的数据。然而,有时 channel 可能会暂时没有数据输入。如果 channel yang tiada apa-apa untuk ditawarkan seketika dan saya mahu goroutine saya melakukan sesuatu yang berbeza. Fungsinya kelihatan seperti ini:

func main () {
    var wg sync.WaitGroup
    arr := make([]*myObject, 0)
    wg.Add(1)
    go listener(c, arr, &wg)
    for {
        // sending stuff to c
    }
}

func listener(c chan *myObject, arr []*myObject, wg *sync.WaitGroup) {
    for {
        select {
        case value := <- c:
            arr = append(arr, value)
        case <- time.After(1 * time.Second):
            fmt.Println(arr)
        }
}

Masalahnya ialah saya mahu melihat semua yang melalui saluran itu dicetak. Jika kedudukan main 突然结束,可能 arr 中还剩下一些东西还没有打印出来,我就看不到了。所以我需要确保这个goroutine在程序结束之前处理完通道中的所有数据。我认为,这意味着我需要使用 WaitGroup 并使用 Wait() 来确保程序在我的 goroutine 完成需要执行的操作之前不会关闭。 但我不知道在我的 WaitGroup 上调用 Done().

Pada asasnya, saya memerlukan cara selamat untuk "menjeda" goroutine sebelum program tamat, dan mencetak apa yang tinggal. Bagaimana saya boleh melakukan ini?

Untuk memburukkan lagi keadaan, untuk perkara seperti ujian unit, saya menghantar data ke saluran sendiri dan selepas menghantar jumlah tertentu, saya ingin melihat tatasusunan. Walau bagaimanapun, jika saya hanya menyemak tatasusunan sejurus selepas kod yang menghantar data ke saluran, goroutine mungkin belum mempunyai peluang untuk memproses semua data lagi. Dalam kes ini, saya mahu menunggu goroutine memproses semua data yang saya hantar, dan kemudian saya mahu menjedanya dan memintanya untuk menunjukkan kepada saya tatasusunan. Tetapi bagaimana saya tahu apabila goroutine telah selesai diproses? Saya boleh sleep tunggu sebentar, beri peluang untuk menyelesaikannya, dan kemudian berhenti dan lihat, tetapi rasanya agak meretas. Saya rasa ada cara amalan terbaik untuk menyelesaikan masalah ini, tetapi saya masih belum mengetahuinya.

Berikut adalah beberapa idea yang saya ada, sifar daripadanya berkesan.

  1. dalam infiniti for 循环之外调用 Done(). Ini tidak berfungsi kerana sejauh yang saya tahu kod itu tidak boleh diakses.

  2. Dalam tamat masacase中调用Done(). Ini tidak berfungsi kerana selepas tamat masa mungkin terdapat lebih banyak data dalam perjalanan dan saya mahu goroutine saya terus mendengar.


Jawapan betul


Ubah suai pendengar untuk kembali apabila saluran ditutup. Panggil wg.Done() apabila kembali:

func listener(c chan *myObject, arr []*myObject, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case value, ok := <- c:
            if !ok { return }
            arr = append(arr, value)
        case <- time.After(1 * time.Second):
            fmt.Println(arr)
        }
}

Ubah suai utama untuk menutup saluran selepas penghantaran selesai. Tunggu goroutine selesai sebelum pulang dari utama.

var wg sync.WaitGroup
arr := make([]*myObject, 0)
wg.Add(1)
go listener(c, arr, &wg)
for {
    // sending stuff to c
}
close(c)
wg.Wait()

Atas ialah kandungan terperinci Cara selamat untuk menamatkan goroutine gelung tak terhingga?. 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