go中的chan是动态的,因此千万不要把chan想象成slice切片类型的数据。
- 只要chan不close可以永远发送数据和接受数据
- 如果channel里面没有数据,接收方会阻塞
- 如果没有人正在等待channel的数据,发送方会阻塞
- 从一个close的channel取数据永远不会阻塞, 同时获取的数据为默认值(与定义的chan类型一致)
下面这段代码,会解释上面这四个chan特点:
package main
import (
"net/http"
"fmt"
"sync"
)
func printUrl(url string) {
res, err := http.Get(url)
if err != nil{
fmt.Println(err)
return
}
defer res.Body.Close()
fmt.Println(url, res.Status)
}
func work2(urls chan string, wg *sync.WaitGroup) {
for{
url, ok := <- urls // 判断取出的数据是否为false 说明chan关闭
if !ok{
break
}
printUrl(url)
}
wg.Done()
}
func work(urls chan string, wg *sync.WaitGroup) {
for i := range urls{ // chan中有一条数据会循环一次知道chan关闭
printUrl(i)
}
wg.Done()
}
func main() {
url := "http://www.baidu.com"
var u []string
for i :=0; i<15;i ++{ // 先生成一些数据
u = append(u, url)
}
wg := new(sync.WaitGroup) // 利用WaitGroup的方式协程同步
//wg.Add(5) // 可一次性添加任务总数
urlchann := make(chan string)
for i:=0; i<5 ;i++ {
wg.Add(1) // 也可每创建一个任务 添加一个标识
go work(urlchann, wg)
}
for _, line := range u{
urlchann <- line // 将任务需要的数据添加到队列中
}
close(urlchann) // 关闭chan
wg.Wait()
}
代码中的Work与Work2效果是一样的。