我正在学习 golang,我想知道是否可以让 goroutine 从一个通道读取输入并将输出写入另一个通道,同时它受 waitgroup 限制?
请看下面的代码
func downloaderInputUrlFromChannel(id int, urlChan chan string, responseChan chan int, wg *sync.WaitGroup) {
for url := range urlChan {
resp, _ := http.Get(url)
fmt.Println("STARTED worker ", id, " For URL ", url, "With Response Code", resp.StatusCode)
responseChan <- resp.StatusCode
fmt.Println("FINISHED worker ", id, " For URL ", url, "With Response Code", resp.StatusCode)
}
defer wg.Done()
}
func main() {
urls := []string{....} // Containing 25 urls
MaxGoroutineCount := 5
var wg sync.WaitGroup
urlChan := make(chan string)
responseChan := make(chan int)
// Start Workers
for i := 0; i < MaxGoroutineCount; i++ {
wg.Add(1)
go downloaderInputUrlFromChannel(i, urlChan, responseChan, &wg)
}
// Fill in the queues
for _, url := range urls {
urlChan <- url
}
close(urlChan)
for i := 0; i < len(urls); i++ {
fmt.Println(<-responseChan)
}
close(responseChan)
wg.Wait()
我没有看到第 FINISHED 行的输出,输出为
STARTED worker 0 For URL https://httpbin.org?q=1,l=2,p=1 With Response Code 200
STARTED worker 4 For URL https://httpbin.org/ With Response Code 200
STARTED worker 2 For URL https://httpbin.org?q=1,r=2,p=1 With Response Code 200
STARTED worker 1 For URL https://httpbin.org?q=1 With Response Code 200
STARTED worker 3 For URL https://httpbin.org?a=1 With Response Code 200
因此,responseChan 通道永远不会被填满,即使我在主通道中使用来自该通道的消息,程序也会卡在此时。如果我完全删除responseChan,程序将按预期工作。并且比顺序运行更快。
我需要 downloaderInputUrlFromChannel 的输出,所以我需要一些频道。 谁能帮助我我做错了什么?
快速修复:使用
responseChan
创建 make(chan int, len(urls))
。
让我们从如何处理渠道开始。对于它们两者,容量都缺失(在
make
内置函数中),因此通道是无缓冲的[1]。
Channel:通道的缓冲区用指定的缓冲区初始化 容量。如果为零或省略大小,则通道是无缓冲的。
这意味着如果在发送之前没有准备好接收器,则执行将被阻止。因此,正如您所知,
urls
存在最大数量,可以按如下方式创建通道:make(chan int, len(urls))
。对于 urlChan
来说并不重要,因为有 5 个 goroutine 接收数据。
正如 @Gimby 提到的,在完全使用完通道后关闭通道是有意义的。在您的情况下,您可以在创建通道后立即推迟
close
调用。尽管如此,它仍然可以工作,因为您在关闭通道之前发送了所有 urls
,并且在收到最后发送的值之前不会发生实际关闭[2]。