【发布时间】:2020-08-24 07:22:16
【问题描述】:
在下面的代码中:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func getPage(url string) (int, error) {
resp, err := http.Get(url)
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
return len(body), nil
}
func getter(urlChan chan string, size chan int) {
url := <-urlChan
length, err := getPage(url)
if err == nil {
size <- length
urlChan <- url
}
}
func main() {
urls := []string{"http://www.google.com/", "http://www.yahoo.com",
"http://www.bing.com", "http://bbc.co.uk"}
sizeChan := make(chan int)
urlChan := make(chan string)
for _, url := range urls {
urlChan <- url
go getter(urlChan, sizeChan)
}
for i := 0; i < len(urls); i++ {
fmt.Printf("%s has length %d\n", <-urlChan, <-sizeChan)
}
}
我使用urlChan 作为双向,以知道计算给定大小(sizeChan)的 url(urlChan)。
对于getter() go-routine,在将第一个字符串参数url 设置为urlChan 后,以下输出显示了挂起情况:
$ go install github.com/shamhub/cs61a
$
$
$ bin/cs61a
1) 如何在通道上进行双向通信?
2) 如何分析给定进程的 go-routines 状态?
【问题讨论】:
-
向进程发送 SIGQUIT 以找出进程挂起的位置。通过频道发送
url是不必要的复杂。通过将url作为参数而不是作为通过通道接收的值传递来简化代码:func getter(url string, size chan int) { ... }。 -
这是不正确的,这将导致不可预测的结果,因为推送到 url 和大小通道可能会在您生成的多个例程中交错。我找不到你会使用相同的通道进行写入然后读取的情况。您的返回频道应该是嵌入了您想要发回的所有必要信息的类型(即:
type xx struct { url string; len int; })。 -
@CeriseLimón 是的,我已经这样做了,但是如何将大小与主 goroutine 中的 url 关联起来?
-
使用
struct { url string; size int }作为通道元素类型。如果您需要知道urls中的索引,则将索引传递给getter并使用struct { index int; size int }作为通道元素类型。 -
@CeriseLimón 我是否需要在
main()中创建元素类型为struct { index int; size int }的频道并传递给getter()?