遍历通道时关闭通道的最佳时间

时间:2019-06-14 18:50:12

标签: go

我正在玩Golang,我创建了这个小应用程序,使用goroutines进行了多个并发的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
    }
} 

2 个答案:

答案 0 :(得分:6)

当没有更多值要发送时,您将关闭通道,因此在这种情况下,所有checkUrl goroutine已完成。

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
    }
}

(请注意,error中的http.Get只会反映连接和协议错误。如果您也希望看到HTTP服务器错误,那么它将不会包含http服务器错误。如何检查路径,而不仅仅是主机。)

答案 1 :(得分:1)

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

注意:处理这种情况的更好方法是扇出,扇入并发模式。请参阅(https://blog.golang.org/pipelinesGo 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
    }
}