package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"time"
)
func main() {
start1 := time.Now()
ch := make(chan string)
for _, url := range os.Args[1:] {
go fetch(url, ch)
}
for range os.Args[1:] {
fmt.Println(<-ch)
}
fmt.Printf("%.2fs elapsed\n", time.Since(start1).Seconds())
}
func fetch(url string, ch chan<- string ) {
start := time.Now()
resp, err := http.Get(url)
if err != nil {
ch <- fmt.Sprint(err)
return
}
bytes, err := io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
if err != nil {
ch <- fmt.Sprintf("while reading,%s : %s", url, err)
return
}
sinces := time.Since(start).Seconds()
ch <- fmt.Sprintf("%.2fs %s %d", sinces, url, nbytes)
}
上面的程序并发的获取多个url 内容,则这个进程使用的时间不会超过耗时最长时间的获取任务,而不是所有获取任务总的时间。
goroutine 是一个并发执行的函数。通道是一种允许某一例程向另一个例程传递指定类型的值的通信机制。
io.Copy函数读取相应的内容,然后通过写入 ioutil.Discard 输出流进行丢弃。Copy 返回字节数以及出现的任何错误。每一个结果返回时, fetch 发送一条汇总信息到通道 ch。
当一个 goroutine 试图在一个通道上进行发送或接收操作时,它会阻塞,直到另一个 goroutine 试图进行接收或发送操作才传递值,并开始处理两个 goroutine 。在本例中,每一个 fetch 在通道 ch 发送一个值 (ch <- expression),main 函数接收它们 (<-ch)。由 main 来处理所有的输出确保了每个 goroutine 作为一个整体单元处理,这样就避免了两个 goroutine 同时完成造成输出交织所带来的风险。