「Go语言进阶」并发编程详解( 二 )


有缓冲通道缓冲通道中的数字表示该通道可以在没有接收者阻塞的情况下缓存多少个元素 。
加入容量为1 , 所以只能缓存一个元素 。如果一个新的元素试图被发送到已经满了的通道中 , 发送者将会阻塞直到接收者从通道中读取一个元素 。
阻塞并不一定意味着数据丢失 , 这取决于阻塞的原因和应用程序的设计:
在 Go 语言中 , 通道是一种同步机制 , 发送者和接收者之间可以通过通道来进行通信 。 如果发送者试图向一个满的缓冲通道发送数据 , 那么发送者将会阻塞直到缓冲区有空间可用 。同样 , 如果接收者试图从一个空的通道接收数据 , 那么接收者将会阻塞直到通道中有数据可用 。这种情况下 , 数据不会丢失 , 而是在缓冲区中等待被取出 。
无缓冲通道但是 , 如果通道是无缓冲的 , 那么发送者和接收者之间将是同步的 。如果发送者在接收者准备好之前发送了数据 , 那么发送者将会阻塞直到接收者准备好 。
如果接收者在数据可用之前就开始接收 , 那么接收者将会阻塞直到数据可用 。在这种情况下 , 如果发送者和接收者之间的时间差较大 , 那么可能会导致数据丢失 。
所以阻塞并不一定意味着数据丢失 , 而是取决于程序是否设计了阻塞的处理方式 , 以及阻塞的类型 。
下面是一个示例代码 , 其中两个 goroutine 通过缓冲通道共享内存:
 package mainimport ("fmt")func main() {// 创建缓冲通道ch := make(chan int, 1)// 启动第一个goroutinego func() {for i := 0; i < 10; i++ {ch <- i // 发送数据}close(ch) // 关闭通道}()// 启动第二个goroutinego func() {for i := range ch {fmt.Println(i) // 接收数据并打印}}()// 等待所有goroutine结束fmt.Scanln()}执行效果:
 

「Go语言进阶」并发编程详解

文章插图
 
在这个示例中 , 第一个 goroutine 会循环发送 0 到 9 的整数 , 而第二个 goroutine 会接收这些整数并打印 。这两个 goroutine 都会共享同一个通道来传递数据 。
注意 , 在生产环境中 , 通常需要使用同步机制来等待 goroutine 结束 , 而不是使用 fmt.Scanln() 。
1.3 Channelmake(chan 元素类型,[缓冲大小])
  • 无缓冲通道 make(chan int) 同步
  • 有缓冲通道 make(chan int,2) 不同步
无缓冲通道是在发送者和接收者之间同步地传递消息 。 发送者会在接收者准备好接收消息之前阻塞 , 接收者会在接收到消息之前阻塞 。这种方式可以保证消息的顺序和每个消息只被接收一次 。
缓冲通道具有一个固定大小的缓冲区 , 发送者和接收者之间不再是同步的 。 如果缓冲区已满 , 发送者会继续执行而不会阻塞;如果缓冲区为空 , 接收者会继续执行而不会阻塞 。这种方式可以提高程序的性能 , 但是可能会导致消息的丢失或重复 。
 package mainimport ( "fmt")func main() { // 创建通道 ch := make(chan int) ch_squared := make(chan int) // 启动A子协程 go func() {for i := 0; i < 10; i++ {ch <- i}close(ch) }() // 启动B子协程 go func() {for i := range ch {ch_squared <- i * i}close(ch_squared) }() //主协程输出结果 for i := range ch_squared {fmt.Println(i) }}执行效果:
 
「Go语言进阶」并发编程详解

文章插图
 
在这个程序中 , A子协程循环发送0~9的数字 , B子协程接收并计算数字的平方 , 最后主协程等待所有子协程完成后输出所有数字的平方 。
注意: