温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

golang语言渐入佳境[20]-协程与通道

发布时间:2020-07-25 11:41:37 来源:网络 阅读:405 作者:jonson_jackson 栏目:开发技术

协程引入

通过状态检查器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)
}

// fmt.Println(<-c)
// fmt.Println(<-c)
// fmt.Println(<-c)
// fmt.Println(<-c)
// fmt.Println(<-c)
// fmt.Println(<-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{
// go checkLink(<-c,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)
}
//下面的代码有一个非常严重的问题,当等待2秒钟之后,l这个地址的字符串全部变为了相同的了。并传递到了所有的协程中。
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]-协程与通道

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI