为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
qq_花开花谢_0 2022-10-04 16:37:32
我写了一个关于并发和通道⤵️的go代码package mainimport (    "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输出是这样的 ⤵️在输出中,我们看到程序未终止。节目未终止的原因是通道尚未关闭,因此无法退出循环。如何关闭通道并修复代码?
查看完整描述

3 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

使用等待组监视写入完成。


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

    var wg sync.WaitGroup

    for _, link := range links {

        wg.Add(1)

        go func(){

            getLink(link, ch)

            wg.Done()

        }()

    }

使用另一个例程侦听该事件并关闭通道。


    go func(){

        wg.Wait()

        close(ch)

    }()

    for msg := range ch {

        fmt.Println(msg)

    }


查看完整回答
反对 回复 2022-10-04
?
青春有我

TA贡献1784条经验 获得超8个赞

如果您只启动N个(即)Go例程,所有这些例程都必然会发回一条消息,那么最简单的方法是在关闭通道之前从通道中读取恰好N条消息。len(links)


不要越过频道;当您不知道将收到多少项目并且想要阅读直到频道关闭时,这是最有用的。而是循环给定的次数:range


// main:


for _ = range links {

    fmt.Println(<-ch)

}


close(ch)


查看完整回答
反对 回复 2022-10-04
?
温温酱

TA贡献1752条经验 获得超4个赞

通过将 WaitGroup 添加到方法中来重构它,getLink


func getLink(link string, wg *sync.WaitGroup, ch chan string)

和频道在呼叫后关闭。wg.Wait()


go func() {

    wg.Wait()

    close(ch)

}()

因此,代码的最终版本如下所示 ⤵️


package main


import (

    "fmt"

    "net/http"

    "sync"

)


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, wg *sync.WaitGroup, ch chan string) {

    defer wg.Done()


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

        ch <- err.Error()

    } else {

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

    }

}


func main() {

    wg := sync.WaitGroup{}

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


    for _, link := range links {

        wg.Add(1)

        go getLink(link, &wg, ch)

    }


    go func() {

        wg.Wait()

        close(ch)

    }()


    for msg := range ch {

        fmt.Println(msg)

    }

}

https://play.golang.org/p/741F8eHrhFP


查看完整回答
反对 回复 2022-10-04
  • 3 回答
  • 0 关注
  • 82 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信