一.本文主要針對以下問題:
1.帶緩沖區的channel
2.在兩個goroutine之間進行消息的交互
3.偶爾會有消息到達,有時又阻塞於沒有消息到達
4.兩個goroutine一直存在
設計思路,首先要保證channel構造完成前,發送和接收的消息都沒有使用channel,不然會導致channel阻塞
二.下面是錯誤的代碼:
1.發送端:
package ioproc import ( "fmt" "time" ) var ChT = make([]chan int,4) func Send(){ fmt.Println("Send entry.....") for i:=0;i<4;i++{ go func(i int){ var temp = 0 ChT[i] = make(chan int,5000) for { time.Sleep(time.Millisecond*1000) temp++ ChT[i] <- temp fmt.Println("Send temp ok,",i,"Send") } }(i) } }
代碼解釋:發送函數部分,1.聲明了一個全局的channel數組變量,ChT[]
2.定義send函數:使用for循環,在每個for循環開啟一個goroutine,並將ChT[i]進行make為緩沖區大小是5000的channel
3.一直執行for循環,往ChT[i]中進行添加數據
2.接收端
package utility import ( "SIPLBS/ioproc" "fmt" ) func Recv(){ for{ select{ case tNumber := <- ioproc.ChT[0]: fmt.Println("the ",0,"routine is ",tNumber) case tNumber := <- ioproc.ChT[1]: fmt.Println("the ",1,"routine is ",tNumber) case tNumber := <- ioproc.ChT[2]: fmt.Println("the ",2,"routine is ",tNumber) case tNumber := <- ioproc.ChT[3]: fmt.Println("the ",3,"routine is ",tNumber) } } }
代碼解釋:接收函數部分:1.定義函數,並在函數中一直for循環,通過select一直接收ChT[i]中的數據
3.main包函數:
func init(){ fmt.Println("init entry......") go ioproc2.Send() go ioproc.Recv() }
4.打印結果:
init entry......
Send entry.....
sendsip begin...
Send temp ok, 1 Send
Send temp ok, 0 Send
Send temp ok, 3 Send
Send temp ok, 2 Send
Send temp ok, 0 Send
Send temp ok, 1 Send
Send temp ok, 3 Send
Send temp ok, 2 Send
Send temp ok, 2 Send
可以看到一直有消息往channel中發送,但是recv的GoRoutine一直未收到消息
三.修改之后的代碼
1.發送端
import ( "fmt" "time" ) var ChT = make([]chan int,4) func init(){ fmt.Println("init entry......") for i := 0 ; i < 4; i++{ ChT[i] = make(chan int,5000) } } func Send(){ fmt.Println("Send entry.....") for i:=0;i<4;i++{ go func(i int){ var temp = 0 for { time.Sleep(time.Millisecond*1000) temp++ ChT[i] <- temp fmt.Println("Send temp ok,",i,"Send") } }(i) } }
2.接收端
package utility import ( "SIPLBS/ioproc" "fmt" ) func Recv(){ for{ select{ case tNumber := <- ioproc.ChT[0]: fmt.Println("the ",0,"routine is ",tNumber) case tNumber := <- ioproc.ChT[1]: fmt.Println("the ",1,"routine is ",tNumber) case tNumber := <- ioproc.ChT[2]: fmt.Println("the ",2,"routine is ",tNumber) case tNumber := <- ioproc.ChT[3]: fmt.Println("the ",3,"routine is ",tNumber) } } }
3.main包程序
func main() { go ioproc2.Send() go utility.Recv() }
代碼解釋:目的是將channel放在send和recv兩個goroutine啟動之前已經准備好,所以將channel的初始化部分放到了先於main執行的init函數中,然后在main函數中起send和recv協程。
4.結果打印:
init entry......
Send entry.....
Send temp ok, 1 Send
Send temp ok, 3 Send
Send temp ok, 2 Send
the 3 routine is 1
the 1 routine is 1
the 2 routine is 1
Send temp ok, 0 Send
the 0 routine is 1
還可以改進代碼,將三個函數都封裝到一個類中進行處理,在類進行初始化的時候,可以把channel進行初始化,
然后開啟goroutine,這樣就可以確保發送和接收的goroutine是在channel准備好的情況下進行執行的。