协程引入
通过状态检查器checkLink,不断的获取切片当中的网址,并且打印了出来。
顺序执行。这也就意味着,一旦我访问google.com等网站就会陷入到等待的状况中。后面的网址无法访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
for _,link := range links{ checkLink(link) }
}
func checkLink(link string){
_,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") return }
fmt.Println(link,"连接上了") }
|
go的协程
在函数的前方,加入go
关键字,代表开辟一个新的协程。
运行一个go语言的程序的时候,都会开辟一个main协程。子协程通过go的关键字来创建。
通过Go的调度器,会将go的协程分配给CPU core取执行。当某一个子协程陷入了暂停或结束,Go的调度器会立即切换到其他的协程工作。因此大大的提高了效率。
但是当前的程序,直接退出了。因为main协程终止以后,子协程全部都会被销毁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
for _,link := range links{ go checkLink(link) } //main协程终止以后,子协程全部都会被销毁 }
func checkLink(link string){
_,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") return }
fmt.Println(link,"连接上了") }
|
channel通道
通道就是实现协程之间的通信。
通道的创建
c:= make(chan string) 代表创建了一个通道,此通道只能够传递字符串类型。
通道实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
fmt.Println(<-c)
}
func checkLink(link string,c chan string){
_,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-"没有连接上" return }
fmt.Println(link,"连接上了") c<-"连接上了" }
|
执行结果
1 2
|
http://www.baidu.com 连接上了 连接上了
|
上面的代码输出的结果为:
意味着百度连接上之后就退出了。这是由于主协程fmt.Println(<-c)陷入等待,当百度的子协程运行完毕,为通道添加信息之后。那么主协程退出,但是其他的协程还没有运行完毕。但是会直接销毁。
通道等待
如果想要全部打印出来,增加了多个等待通道的指令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
for i:=0;i<len(links);i++{ fmt.Println(<-c) } }
func checkLink(link string,c chan string){
_,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-"没有连接上" return }
fmt.Println(link,"连接上了") c<-"连接上了" }
|
执行结果
1 2 3 4 5 6 7 8 9 10
|
http://www.baidu.com 连接上了 连接上了 http://www.163.com 连接上了 连接上了 http://www.taobao.com 连接上了 连接上了 http://www.sohu.com 连接上了 连接上了 http://www.jd.com 连接上了 连接上了
|
并不是顺序执行的。
通道无限循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
for{ go checkLink(<-c,c) }
}
func checkLink(link string,c chan string){
_,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-link return }
fmt.Println(link,"连接上了") c<-link }
|
go的通道遍历
比上一个代码效果一样,更加的清晰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
package main
import ( "net/http" "fmt" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
for l:=range c{ go checkLink(l,c) }
}
func checkLink(link string,c chan string){ time.Sleep(2*time.Second) _,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-link return }
fmt.Println(link,"连接上了") c<-link }
|
高级写法的错误代码
下面的代码有一个非常严重的问题,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
package main
import ( "net/http" "fmt" )
func main(){ links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
for l:=range c{ go func() { time.Sleep(2*time.Second) checkLink(l,c) }() } }
func checkLink(link string,c chan string){ _,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-link return } fmt.Println(link,"连接上了") c<-link }
|
更高级的正确写法
上面写法的改进,不再是引用,而是每一个副本。传递到函数中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
package main
import ( "net/http" "fmt" "time" )
func main(){
links := []string{ "http://www.baidu.com", "http://www.jd.com", "http://www.taobao.com", "http://www.163.com", "http://www.sohu.com", }
c:= make(chan string) for _,link := range links{ go checkLink(link,c) }
for l:=range c{ go func(link string) { time.Sleep(2*time.Second) checkLink(link,c) }(l) } }
func checkLink(link string,c chan string){ _,err := http.Get(link) if err !=nil{ fmt.Printf(link,"没有连接上") c<-link return } fmt.Println(link,"连接上了") c<-link }
|
本文链接: https://dreamerjonson.com/2018/11/27/golang-20-channel/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处!
![golang语言渐入佳境[20]-协程与通道 golang语言渐入佳境[20]-协程与通道](/default/index/img?u=aHR0cHM6Ly9jYWNoZS55aXN1LmNvbS91cGxvYWQvaW5mb3JtYXRpb24vMjAyMDAzMTIvNjUvMjM4ODQ1LmpwZw==)