Analisis perangkap WaitGroup Golang dan selesaikan masalah

藏色散人
Lepaskan: 2021-09-14 15:57:02
ke hadapan
1987 orang telah melayarinya

Artikel ini diperkenalkan kepada anda melalui lajur go language tentang perangkap WaitGroup Golang, saya harap ia dapat membantu rakan yang memerlukan.

sync.WaitGroup ialah struktur data yang sangat biasa digunakan dalam persekitaran serentak, digunakan untuk menunggu tamatnya semua coroutine menulis kod, saya hanya mengikuti contoh, dan saya tidak perlu mendalami penggunaannya. Beberapa hari yang lalu, saya tertanya-tanya sama ada saya boleh melaksanakan fungsi Add() dalam coroutine Jawapannya adalah tidak.

Perangkap terletak pada urutan panggilan bagi tiga fungsi WaitGroup. Mari kita semak dahulu fungsi tiga fungsi:

  1. Add(delta int): Tambahkan delta ke kaunter, contohnya, naikkan 1 apabila memulakan coroutine.
  2. Done(): Dilaksanakan sebelum coroutine keluar, kurangkan kaunter sebanyak 1.
  3. Wait(): Kaunter menunggu yang menyekat ialah 0.

Lakukan ujian

Atur cara berikut mencipta bapa coroutine, dan kemudian coroutine bapa mencipta 10 sub-coroutine Fungsi utama menunggu semua coroutine selesai dan kemudian keluar. Lihat Lihat jika terdapat apa-apa yang salah dengan kod di bawah?

package main

import (
    "fmt"
    "sync"
)

func father(wg *sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()

    fmt.Printf("father\n")
    for i := 0; i < 10; i++ {
        go child(wg, i)
    }
}

func child(wg *sync.WaitGroup, id int) {
    wg.Add(1)
    defer wg.Done()

    fmt.Printf("child [%d]\n", id)
}

func main() {
    var wg sync.WaitGroup
    go father(&wg)

    wg.Wait()
    log.Printf("main: father and all chindren exit")
}
Salin selepas log masuk

Adakah anda menemui masalahnya? Jika anda tidak melihat hasil berjalan berikut: fungsi utama mula tamat sebelum sub-coroutine tamat.

father
main: father and all chindren exit
child [9]
child [0]
child [4]
child [7]
child [8]
Salin selepas log masuk

Analisis Perangkap

Sebab bagi masalah di atas ialah fungsi Add() dilaksanakan dalam coroutine selepas coroutine dicipta, dan pada masa ini fungsi Wait() mungkin sudah dilaksanakan, malah fungsi Wait() dilaksanakan sebelum semua Add() dilaksanakan Apabila Wait() dilaksanakan, ia serta-merta memenuhi pembilang WaitGroup 0, Tunggu tamat dan program utama. keluar, menyebabkan semua sub-coroutine Sebelum ia keluar sepenuhnya, fungsi utama tamat.

Pendekatan yang betul

Fungsi Tambah mesti dilaksanakan sebelum fungsi Tunggu dilaksanakan Ini dicadangkan dalam dokumentasi fungsi Tambah: Perhatikan bahawa panggilan dengan delta positif yang berlaku apabila pembilang adalah sifar mesti berlaku sebelum Tunggu..

Bagaimana untuk memastikan bahawa fungsi Tambah mesti dilaksanakan sebelum fungsi Tunggu? Dalam kes coroutine, kami tidak boleh meramalkan sama ada masa pelaksanaan kod dalam coroutine lebih awal daripada masa pelaksanaan fungsi Tunggu Walau bagaimanapun, kami boleh memastikan bahawa dengan melaksanakan fungsi Tambah sebelum menetapkan coroutine dan kemudian melaksanakan Tunggu. fungsi.

Berikut ialah program yang diubah suai dan hasil output.

package main

import (
    "fmt"
    "sync"
)

func father(wg *sync.WaitGroup) {
    defer wg.Done()

    fmt.Printf("father\n")
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go child(wg, i)
    }
}

func child(wg *sync.WaitGroup, id int) {
    defer wg.Done()
    fmt.Printf("child [%d]\n", id)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go father(&wg)

    wg.Wait()
    fmt.Println("main: father and all chindren exit")
}
Salin selepas log masuk
father
child [9]
child [7]
child [8]
child [1]
child [4]
child [5]
child [2]
child [6]
child [0]
child [3]
main: father and all chindren exit
Salin selepas log masuk

Atas ialah kandungan terperinci Analisis perangkap WaitGroup Golang dan selesaikan masalah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:segmentfault.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