【问题标题】:Best time to close channel, when iterating over channel迭代通道时关闭通道的最佳时间
【发布时间】:2019-06-15 14:26:57
【问题描述】:

我正在玩 Golang,我创建了这个小应用程序来使用 goroutine 进行多个并发 api 调用。

在应用运行时,调用完成后,应用卡住了,这是有道理的,因为它无法退出 range c 循环,因为通道未关闭。

我不确定在这种模式下在哪里更好地关闭通道。

package main

import "fmt"
import "net/http"

func main() {
    links := []string{
        "https://github.com/fabpot",
        "https://github.com/andrew",
        "https://github.com/taylorotwell",
        "https://github.com/egoist",
        "https://github.com/HugoGiraudel",
    }

    checkUrls(links)
}

func checkUrls(urls []string) {
    c := make(chan string)

    for _, link := range urls {
        go checkUrl(link, c)
    }

    for msg := range c {
        fmt.Println(msg)
    }

    close(c) //this won't get hit
}

func checkUrl(url string, c chan string) {
    _, err := http.Get(url)

    if err != nil {
        c <- "We could not reach:" + url
    } else {
        c <- "Success reaching the website:" + url
    }
} 

【问题讨论】:

    标签: go


    【解决方案1】:

    当没有更多值要发送时,你关闭了一个通道,所以在这种情况下,它是所有checkUrl goroutines 都完成的时候。

    var wg sync.WaitGroup
    
    func checkUrls(urls []string) {
        c := make(chan string)
    
        for _, link := range urls {
            wg.Add(1)
            go checkUrl(link, c)
        }
    
        go func() {
            wg.Wait()
            close(c)
        }()
    
        for msg := range c {
            fmt.Println(msg)
        }
    }
    
    func checkUrl(url string, c chan string) {
        defer wg.Done()
        _, err := http.Get(url)
    
        if err != nil {
            c <- "We could not reach:" + url
        } else {
            c <- "Success reaching the website:" + url
        }
    }
    

    (请注意,http.Get 中的 error 只会反映连接和协议错误。如果您也期望这些错误,它不会包含 http 服务器错误,您必须看到自己的情况检查路径,而不仅仅是主机。)

    【讨论】:

    • 光滑的解决方案。谢谢!
    【解决方案2】:

    在 Go 中使用通道和 goroutine 编写程序时,始终考虑谁(哪个函数)拥有通道。我更喜欢让拥有频道的功能关闭它的做法。如果我要写这个,我会如下所示。

    注意:处理此类情况的更好方法是扇出、扇入并发模式。参考(https://blog.golang.org/pipelines)Go Concurrency Patterns

    package main
    
    import "fmt"
    import "net/http"
    import "sync"
    
    func main() {
        links := []string{
            "https://github.com/fabpot",
            "https://github.com/andrew",
            "https://github.com/taylorotwell",
            "https://github.com/egoist",
            "https://github.com/HugoGiraudel",
        }
    
    
        processURLS(links)
        fmt.Println("End of Main")
    }
    
    func processURLS(links []string) {
        resultsChan := checkUrls(links)
    
        for msg := range resultsChan {
            fmt.Println(msg)
        }
    
    }     
    
    func checkUrls(urls []string) chan string {
    
        outChan := make(chan string)
    
        go func(urls []string) {
           defer close(outChan)
    
           var wg sync.WaitGroup
           for _, url := range urls {
             wg.Add(1)
              go checkUrl(&wg, url, outChan)
           }
           wg.Wait()
    
        }(urls)
    
        return outChan
    }
    
    func checkUrl(wg *sync.WaitGroup, url string, c chan string) {
        defer wg.Done()
        _, err := http.Get(url)
    
        if err != nil {
            c <- "We could not reach:" + url
        } else {
            c <- "Success reaching the website:" + url
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 2015-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-20
      相关资源
      最近更新 更多