1. 程式人生 > >golang語言漸入佳境[20]-協程與通道

golang語言漸入佳境[20]-協程與通道

協程引入

通過狀態檢查器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