熟悉了并发性,因此开始编写一个简单的带有并发调用的ping cli(让我们忽略我并不是真正在测量ping).

问题是,我不能在等待所有大猩猩程序结束的同时,正确地关闭距离循环的通道. 如果我想并发调用ping函数,则无法将其与等待组同步,因为我将在所有Goroutine完成之前到达wg.Wait()行.

有没有办法让ping调用保持并发,并在它们完成后关闭通道,这样范围循环就可以退出?

func main() {
    domain := flag.String("domain", "google.com", "the domain u want to ping")
    flag.Parse()

    sum := 0
    ch := make(chan int)

    go start_pings(*domain, ch)

    for elapsed := range ch {
        fmt.Println("Part time: " + strconv.Itoa(elapsed))
        sum += elapsed
    }

    avg := sum / 3
    fmt.Println("Average: " + strconv.Itoa(avg))
}

func start_pings(domain string, ch chan int) {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go ping(domain, ch, wg)
    }
    wg.Wait()
    close(ch)
}

func ping(domain string, ch chan int, wg sync.WaitGroup) {
    url := "http://" + domain
    start := time.Now()

    fmt.Println("Start pinging " + url + "...")

    resp, err := http.Get(url)
    elapsed := time.Now().Sub(start)

    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()

    ch <- int(elapsed)
    wg.Done()
}

推荐答案

You must not copy a 100!它的文件明确规定:

第一次使用后,不得复制WaitGroup.

传递一个指向它的指针:wg *sync.WaitGroup.并推迟拨打wg.Done()!您还有另外return条语句将导致跳过wg.Done()条语句!

func start_pings(domain string, ch chan int) {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go ping(domain, ch, &wg)
    }
    wg.Wait()
    close(ch)
}

func ping(domain string, ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    url := "http://" + domain
    start := time.Now()

    fmt.Println("Start pinging " + url + "...")

    resp, err := http.Get(url)
    elapsed := time.Since(start)

    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()

    ch <- int(elapsed)
}

今天的《集成开发环境》(和《黄金人》)对这种明显的误用提出了警告.要避免此类错误,请首先将wg声明为指针:

func start_pings(domain string, ch chan int) {
    wg := &sync.WaitGroup{} // Pointer!
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go ping(domain, ch, wg)
    }
    wg.Wait()
    close(ch)
}

这就减少了错误和误用的空间.

Go相关问答推荐

为什么工具链指令在这种情况下没有效果?

允许在 struct 中使用复合作为函数参数

如何使用工作区方法扩展克隆的Golang库

戈姆:如何将一对一联系起来?

提供的client_secret与此帐户上任何关联的SetupIntent都不匹配

迭代字符串并用映射值替换原始字符串中的值的惯用方法

使用goroutines在Golang中验证 struct

使用 LINQ 对内部数组进行排序

也许在 golang 中包(字符串和字符串类型不匹配)

emersion/go-imap - imap.FetchRFC822:无效内存地址或零指针取消引用

拆分文本并按空格获取字符串数组,如果文本长度超过 500,则获取字符串数组

此代码如何生成内存对齐切片?

Golang泛型在用作 map 元素时不起作用

go 是否对 struct 使用空间填充之类的东西?

Golang 数据库/sql 与 SetMaxOpenConns 挂起

为什么 x/net/html Token().Attr 上的 len 在此处为空切片返回非零值?

Golang 泛型

无法识别同步错误.使用一次

如何断言类型是指向golang中接口的指针

Go 泛型是否与 LINQ to Objects 等效?