在下面的代码中:
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
作为双向,以了解给定大小(urlChan
)的url(sizeChan
)。
对于getter()
例程,在将第一个字符串参数url
设置为urlChan
后,下面的输出显示挂起情况:
$ go install github.com/shamhub/cs61a
$
$
$ bin/cs61a
1)如何在通道上执行双向通信?
2)如何描述给定进程的例行程序状态?
您必须阅读和练习Go导览,我相信下面的代码中使用的每个细节都将在此处进行解释,但是,这是一个解决方案
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"sync"
)
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
}
type result struct {
url string
len int
err error
}
func main() {
urls := []string{"http://www.google.com/", "http://www.yahoo.com",
"http://www.bing.com", "http://bbc.co.uk"}
resChan := make(chan result)
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
l, err := getPage(url)
resChan <- result{url: url, len: l, err: err}
}(url)
}
go func() {
wg.Wait()
close(resChan)
}()
for r := range resChan {
if r.err != nil {
log.Printf("failed to fetch %q: %v\n", r.url, r.err)
continue
}
fmt.Printf("%s has length %d\n", r.url, r.len)
}
}
这是不理想的,因为它不会限制并发传出请求的数量。
关于,2) How to profile the status of go-routines for a given process?
请参阅pprof工具。有一个文档https://golang.org/doc/diagnostics.html
正如其他人已经指出的,您可以更简单地解决此问题:
type sized struct {
url string
length int
err error
}
func sizer(url string, result chan<- sized, wg *sync.WaitGroup) {
defer wg.Done()
length, err := getPage(url)
result <- sized{url, length, err}
}
func main() {
urls := []string{"http://www.google.com/", "http://www.yahoo.com",
"http://www.bing.com", "http://bbc.co.uk"}
ch := make(chan sized)
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go sizer(url, ch, &wg)
}
go func() {
wg.Wait()
close(ch)
}()
for result := range ch {
if result.err != nil {
fmt.Printf("%s: %s\n", result.url, result.err)
} else {
fmt.Printf("%s: length = %d\n", result.url, result.length)
}
}
}
Complete example on playground, though it can't dial out, so not really useful there.
如何在通道上进行双向通信?
您不能。
嗯,那不是完全正确的。让我们说相反:您不应。
假设我们有一个频道:
var ch chan T
对于某些类型T。
频道本身本质上是...好吧,我认为非定向是正确的词:
ch <- val
]将类型T的任何值放入通道var <- ch
]从通道中取出任何类型T的值这显然不是单向的,但我认为称它为[[双向”是一种误导:它具有“将事物放入”一侧和“取出事物”一侧,两者都集中在一个通道实例中,但是通道与任何特定的user
ch
为buffered
,则X和Y之一或两者都可以放入项目,然后A和B之一或两者都放入。可以取出物品。项目将按其进入的顺序出现,从而序列化访问;如果频道已满,则尝试放入项目的操作将被阻止;但是项目不专门转移从 X 至Y。特别是:// Y: paused or stopped
// do this in X when ch is initially empty:
ch <- T{}
v := <-ch
这里,X将零值T
放入通道,然后将其取出。这不是定向的。 X返回了[[自己的数据。
如果通道不是为空,但也未满,则X或Y都可以向其中添加某些内容(作为队列),然后从队列的最前面删除某些内容。但这只是将频道用作队列。 (请参见Is it possible to use Go's buffered channel as a thread-safe queue?)
如果此队列具有某些它肯定缺乏的功能,则您[[可以使用单个队列进行某种双向通信(请参阅Is two way comm possible using a single message queue in C)。但是它没有它们。如果确实需要双向通信,答案很明显:使用两个队列。将一个队列(一个通道)指定为X发送到Y通道,将另一个队列指定为Y发送到X通道。
1可以通过unsafe
访问/恢复基础通道,但是除非您确切地知道自己在做什么,否则不要这样做。向您传递了单向实例的某人可能不希望您使用该通道的另一侧。