Golang协程间的通信

本文深入探讨了Golang中的协程及其通信机制。通过通道(channel),协程实现同步和数据交换。文章详细介绍了无缓冲与带缓冲的channel用法,以及如何关闭和检查通道状态。此外,还讨论了使用select进行协程切换和选择的应用场景,以应对多生产者消费者问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通道(channel)是Golang中协程之间通信的重要方式

协程
  • Golang中的协程和其它语言中定义的协程不太一样,Golang中的协程更倾向于并行;
协程之间的通信
  • 协程之间通过channel进行通信,对于未指定缓冲的channel来说必须等待其它的协程来写或读才能继续执行剩下的语句(生产-消费),这也是协程之间阻塞的方式。
    • channel的使用:
      	package main
      	import (
      		"fmt"
      		"time"
      	)
      
      	func channelWrite(ch chan int){
      		ch<-5//写入数据
      		fmt.Println("I've  written it.")//写入以后阻塞,直到被读出以后才能执行打印语句
      	}
      	func channelRead(ch chan int){
      		time.Sleep(3*1e9)
      		fmt.Println("Read from a channel",<-ch)//读取数据以后才能解除阻塞
      	}
      	func main(){
      		ch:=make(chan int)
      		go channelWrite(ch)
      		go channelRead(ch)
      		time.Sleep(5*1e9)
      	}
      
    • 带缓冲的channel:
      前面的阻塞方式效率相对较低,可以通过指定缓冲区,只有当缓冲区满时才阻塞
      	package main
      	import (
      		"fmt"
      		"time"
      	)
      
      	func channelWrite(ch chan int){
      		ch<-5//写入数据
      		fmt.Println("I've  written it.")//缓冲区未满,因此直接执行打印语句
      	}
      	func channelRead(ch chan int){
      		time.Sleep(3*1e9)
      		fmt.Println("Read from a channel",<-ch)//缓冲区未满,无法阻塞
      	}
      	func main(){
      		ch:=make(chan in,5)//指定缓冲size=5
      		go channelWrite(ch)
      		go channelRead(ch)
      		time.Sleep(5*1e9)
      	}
      
协程的关闭:
  • 协程在不需要再写入数据时需要关闭通道,使用close(ch)即可手动关闭一个通道,应当在每次创建一个通道时defer close(ch),避免错误的产生
    • 为了避免读取到已关闭的通道,每次读取操作时应当判断通道是否关闭:
    	if v,ok:=<-ch;ok{
    	...
    	}
    
协程的切换/选择:
  • 在生产者消费者模型中比较常见的就是多个生产者生产不同的物品,多个消费者消费不同的物品,这种场景下通常使用select处理不同协程之间的通信
    	func writeChan1(ch1 chan int){
    		for i:=0;i<100;i++ {
    			ch1 <-i
    		}
    	}
    	func writeChan2(ch2 chan int){
    		for i:=0;i<100;i++ {
    			ch2 <-i
    		}
    	}
    	func selectFunc(ch1,ch2 chan int){
    		for{
    		select{
    		case val:=<-ch1:
    				fmt.Printf("Got %v from channel 1\n",val)
    		case val:=<-ch2:
    				fmt.Printf("Got %v from channel 2\n",val)
    		}
    	}
    
    	}
    	func main(){
    		ch1:=make(chan int)
    		ch2:=make(chan int)
    		defer close(ch1)
    		defer close(ch2)
    		go writeChan1(ch1)
    		go writeChan2(ch2)
    		go selectFunc(ch1,ch2)
    		time.Sleep(1e9)
    	}
    
    
    
    • select 执行类似switch,当所有的channel没有数据写入时,select阻塞直到有任何一个满足执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值