溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發(fā)布時間:2020-07-25 11:41:37 來源:網(wǎng)絡 閱讀:407 作者:jonson_jackson 欄目:開發(fā)技術

協(xié)程引入

通過狀態(tài)檢查器checkLink,不斷的獲取切片當中的網(wǎng)址,并且打印了出來。
順序執(zhí)行。這也就意味著,一旦我訪問google.com等網(wǎng)站就會陷入到等待的狀況中。后面的網(wǎng)址無法訪問。

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的協(xié)程

在函數(shù)的前方,加入go關鍵字,代表開辟一個新的協(xié)程。

運行一個go語言的程序的時候,都會開辟一個main協(xié)程。子協(xié)程通過go的關鍵字來創(chuàng)建。
通過Go的調(diào)度器,會將go的協(xié)程分配給CPU core取執(zhí)行。當某一個子協(xié)程陷入了暫?;蚪Y束,Go的調(diào)度器會立即切換到其他的協(xié)程工作。因此大大的提高了效率。

但是當前的程序,直接退出了。因為main協(xié)程終止以后,子協(xié)程全部都會被銷毀。

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協(xié)程終止以后,子協(xié)程全部都會被銷毀
}

func checkLink(link string){

_,err := http.Get(link)
if err !=nil{
fmt.Printf(link,"沒有連接上")
return
}

fmt.Println(link,"連接上了")
}

channel通道

通道就是實現(xiàn)協(xié)程之間的通信。

通道的創(chuàng)建

c:= make(chan string) 代表創(chuàng)建了一個通道,此通道只能夠傳遞字符串類型。

通道實例

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){ //通道的參數(shù)

_,err := http.Get(link)
if err !=nil{
fmt.Printf(link,"沒有連接上")
c<-"沒有連接上"    //為通道傳遞消息
return
}

fmt.Println(link,"連接上了")
c<-"連接上了"//為通道傳遞消息
}

執(zhí)行結果

1
2
http://www.baidu.com 連接上了
連接上了

上面的代碼輸出的結果為:
意味著百度連接上之后就退出了。這是由于主協(xié)程fmt.Println(<-c)陷入等待,當百度的子協(xié)程運行完畢,為通道添加信息之后。那么主協(xié)程退出,但是其他的協(xié)程還沒有運行完畢。但是會直接銷毀。

通道等待

如果想要全部打印出來,增加了多個等待通道的指令。

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<-"連接上了"
}

執(zhí)行結果

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 連接上了
連接上了

并不是順序執(zhí)行的。

通道無限循環(huán)

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)   //一旦接收到通道的信息,就再次的創(chuàng)建協(xié)程,將鏈接作為第一個參數(shù)。
}


}

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)
}
//下面的代碼有一個非常嚴重的問題,當?shù)却?秒鐘之后,l這個地址的字符串全部變?yōu)榱讼嗤牧?。并傳遞到了所有的協(xié)程中。
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
}

更高級的正確寫法

上面寫法的改進,不再是引用,而是每一個副本。傳遞到函數(shù)中。

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)
}

//無限遍歷通道。   匿名函數(shù)的方式
for l:=range c{
go func(link string) {    //上面寫法的改進,不再是引用,而是每一個副本。首先傳遞到函數(shù)中。
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協(xié)議 許可協(xié)議。轉載請注明出處!

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

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI