我正在玩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
}
}
答案 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/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
}
}