Golang协程间的通信

通道(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阻塞直到有任何一个满足执行

你可能感兴趣的:(Golang)