如何在并发操作中关闭通道?

我写了一个关于并发和通道⤵️的go代码

package main


import (

    "fmt"

    "net/http"

)


var links = []string{

    "https://mcevik.com",

    "https://stackoverflow.com",

    "https://www.linkedin.com",

    "https://github.com",

    "https://medium.com",

    "https://kaggle.com",

}


func getLink(link string, ch chan string) {

    if res, err := http.Get(link); err != nil {

        ch <- err.Error()

    } else {

        ch <- fmt.Sprintf("[%d] - %s", res.StatusCode, link)

    }

}


func main() {

    ch := make(chan string, len(links))


    for _, link := range links {

        go getLink(link, ch)

    }


    for msg := range ch {

        fmt.Println(msg)

    }

}

https://play.golang.org/p/Uz_k8KI6bKt


输出是这样的 ⤵️

http://img1.mukewang.com/633bf0ed0001575914720441.jpg

在输出中,我们看到程序未终止。节目未终止的原因是通道尚未关闭,因此无法退出循环。

如何关闭通道并修复代码?


qq_花开花谢_0
浏览 91回答 3
3回答

Cats萌萌

使用等待组监视写入完成。&nbsp; &nbsp; ch := make(chan string, len(links))&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for _, link := range links {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getLink(link, ch)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }使用另一个例程侦听该事件并关闭通道。&nbsp; &nbsp; go func(){&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; }()&nbsp; &nbsp; for msg := range ch {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(msg)&nbsp; &nbsp; }

青春有我

如果您只启动N个(即)Go例程,所有这些例程都必然会发回一条消息,那么最简单的方法是在关闭通道之前从通道中读取恰好N条消息。len(links)不要越过频道;当您不知道将收到多少项目并且想要阅读直到频道关闭时,这是最有用的。而是循环给定的次数:range// main:for _ = range links {&nbsp; &nbsp; fmt.Println(<-ch)}close(ch)

温温酱

通过将 WaitGroup 添加到方法中来重构它,getLinkfunc getLink(link string, wg *sync.WaitGroup, ch chan string)和频道在呼叫后关闭。wg.Wait()go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ch)}()因此,代码的最终版本如下所示 ⤵️package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "sync")var links = []string{&nbsp; &nbsp; "https://mcevik.com",&nbsp; &nbsp; "https://stackoverflow.com",&nbsp; &nbsp; "https://www.linkedin.com",&nbsp; &nbsp; "https://github.com",&nbsp; &nbsp; "https://medium.com",&nbsp; &nbsp; "https://kaggle.com",}func getLink(link string, wg *sync.WaitGroup, ch chan string) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; if res, err := http.Get(link); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; ch <- err.Error()&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; ch <- fmt.Sprintf("[%d] - %s", res.StatusCode, link)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; wg := sync.WaitGroup{}&nbsp; &nbsp; ch := make(chan string, len(links))&nbsp; &nbsp; for _, link := range links {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go getLink(link, &wg, ch)&nbsp; &nbsp; }&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; }()&nbsp; &nbsp; for msg := range ch {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(msg)&nbsp; &nbsp; }}https://play.golang.org/p/741F8eHrhFP
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go