go语言中带缓冲区的channel的使用
一.本文主要针对以下问题:
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准备好的情况下进行执行的。

浙公网安备 33010602011771号