在 Goroutine 中延迟调用sync.WaitGroup.Wait():为什么这会起作用?

我试图理解负载测试工具/库的源代码中的Attack()函数(https://github.com/tsenart/vegeta/blob/44a49c878dd6f28f04b9b5ce5751490b0dce1e18/lib/attack.go#L253-L312vegeta ) 。我创建了一个简化的示例:


package main


import (

    "fmt"

    "sync"

    "time"

)


func main() {

    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {

        wg.Add(1)

        go attack(&wg)

    }

    // wg.Wait()


    go func() {

        defer wg.Wait()

    }()

}


func attack(wg *sync.WaitGroup) {

    defer wg.Done()

    time.Sleep(1 * time.Second)

    fmt.Println("foobar")

}

我注意到这个函数立即返回而没有打印foobar10 次。仅当wg.Wait()我看到该行中的注释foobar在 1 秒后打印了 10 次时。这对我来说很有意义,因为函数在调用main()之前返回。wg.Wait()

该attack()方法读取的位置


func (a *Attacker) attack(tr Targeter, name string, workers *sync.WaitGroup, ticks <-chan struct{}, results chan<- *Result) {

    defer workers.Done()

    for range ticks {

        results <- a.hit(tr, name)

    }

}

我不明白为什么该Attack()函数在不调用的情况下不会立即返回attack(),因为它wg.Wait()位于 Goroutine 内部?


慕丝7291255
浏览 124回答 1
1回答

红颜莎娜

vegeta 也会Attack立即返回,但通道中填充有仍在运行的 goroutine。一旦这些完成,通道就会关闭(defer close(results)),从而启用必须检测完成的代码result。例子;package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; results := attacks()&nbsp; &nbsp; fmt.Println("attacks returned")&nbsp; &nbsp; for result := range results {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(result)&nbsp; &nbsp; }}func attacks() chan string {&nbsp; &nbsp; // A channel to hold the results&nbsp; &nbsp; c := make(chan string)&nbsp; &nbsp; // Fire 10 routines populating the channel&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; attack(c)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }&nbsp; &nbsp; // Close channel once routines are finished&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(c)&nbsp; &nbsp; }()&nbsp; &nbsp; //&nbsp; &nbsp; return c}func attack(c chan<- string) {&nbsp; &nbsp; time.Sleep(1 * time.Second)&nbsp; &nbsp; c <- "foobar"}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go