这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
channel
通道是Go中的一种通信机制
Go语言的理念: 通过通信来共享内存, 而不是通信共享内存来通信
在goroutine之间通过通道来进行消息的发送和接收
通道也是有类型的, 一个通道只能传递同一种类型的值
通道默认是阻塞的, 除非在创建通道时指明它的缓冲区大小
格式
var xxx chan 数据类型
定义不同类型的通道
// 定义整型通道
chI := make(chan int)
fmt.Printf("%#v \n", chI)
// 定义布尔型通道
chB := make(chan bool)
fmt.Printf("%#v \n", chB)
// 定义结构体类型通道
chPerson := make(chan Person)
fmt.Printf("%#v \n", chPerson)
通道的操作
// 通道的发送 通道标识符 <- 通道对应类型的数据
// 无缓冲通道, 如果没有一个协程去接收这个通道的值, 程序会被阻塞
//ch0 := make(chan int)
// 有缓冲通道
ch0 := make(chan int, 2)
// 通道在左, 数据在右, 表明向通道中发送数据
ch0 <- 10
ch0 <- 20
// 通道的关闭
close(ch0)
// 通道的接收 变量标签符 = <- 通道标识符
//value := <- ch0
//value2 := <- ch0
//fmt.Println("通道中的值: ", value)
//fmt.Println("通道中的值: ", value2)
// 使用for...range来从通道中取值
for v := range ch0 {
if v == 0 {
break
}
fmt.Println("通道ch0中的值: ", v)
}
定义只发送通道
// 只能向通道中写入数据, 而不能从通道中取出数据
ch3 := make(chan<- int)
fmt.Printf("%#v \n", ch3)
定义只接收通道
// 只能从通道中取出数据, 而不能向通道中写入数据
ch4 := make(<-chan int)
fmt.Printf("%#v \n", ch4)
发送通道接收通道的使用
func sendCh0(ch chan <- int) {
fmt.Println("sendCh0 向通道中发送值")
// 通道的发送 通道标识符 <- 通道对应类型的数据
ch <- 10
}
func receiveCh0(ch <- chan int) {
// 通道的接收 变量标签符 = <- 通道标识符
value := <- ch
fmt.Println("receiveCh0 从通道中接收的值为: ", value)
}
func main() {
ch0 := make(chan int)
go sendCh0(ch0)
go receiveCh0(ch0)
}
同步通道
func sendData(ch chan <- int) {
for i := 0; i < 5; i++ {
fmt.Println("要发送的数据: ", i)
ch <- i
fmt.Println("已发送的数据: ", i)
}
}
func receiveData(ch <- chan int) {
for v := range ch {
fmt.Println("已接收的数据~~~~~~: ", v)
}
}
// 对于同步通道来说, 当向通道中发送一条数据后, 只能等着通道中的值被接收后, 才能发送下一条数据.
ch5 := make(chan int)
//ch5 := make(chan int, 1)
go sendData(ch5)
go receiveData(ch5)
time.Sleep(time.Second * 3)
异步通道
// 对于异步通道来说, 当通道的缓冲区满的时候, 才会阻塞发送数据所在协程
ch5 := make(chan int, 1)
go sendData(ch5)
go receiveData(ch5)
time.Sleep(time.Second * 3)
同步通道和异步通道注意事项
如果是不带缓冲区的通道 如果往通道时发送数据后, 没有被接收, 那么这个通道继续被阻塞, 直到数据被接收
无缓冲通道, 又称为同步通道 在没给通道发送数据前, 可以向通道中发送数据, 不能从通道中接收数据 也就是接收通道所在协程阻塞
在给通道发送数据后, 可以从通道中接收数据, 不能向通道中发送数据 也就是发送通道所在协程阻塞
如果是带缓冲区的通道 如果缓冲区没满, 则可以继续往通道里发送数据, 否则才被阻塞
有缓冲通道, 又称为异步通道 在缓冲区没满前, 可以向通道中发送数据 直到缓冲区满, 发送通道所在协程阻塞
如果缓冲区有数据, 则可以从通道中接收数据 直到缓冲区空, 接收通道所在协程阻塞
通道在select中的使用
当有多个通道需要操作时
如果某个通道缓冲区空, 从该通道中接收数据就会阻塞
如果某个通道缓冲区满, 向该通道中发送数据就会阻塞
可以使用select语句来解决多通道操作的问题
ch6 := make(chan int, 1)
ch7 := make(chan int, 1)
for i := 0; i < 10; i++ {
select {
case ch6 <- i:
fmt.Println("向ch6通道中已发送值: ", i)
case v := <- ch6:
fmt.Println("从ch6通道中接收值: ", v)
case ch7 <- i:
fmt.Println("向ch7通道中已发送值: ", i)
case v := <- ch7:
fmt.Println("从ch7通道中接收值: ", v)
}
}
总结
Go中的通道给我们带来了一种新的并发模型中的通信机制: 通过通道通信来共享内存, 而不是通过共享内存来通信. 这给我们带来了更安全的内存访问和协程间的同步机制. 我好像喜欢上了这个通信理念!!!