Golang入门——channel的进阶使用

单向管道

顾名思义,单向管道就是只能用于发送或者接收数据。从管道的数据结构上看,并没有单向的管道。所谓的单向管道就是对管道的一种限制。

func readChannel(ChanName <-chan int){ ... }
func writeChannel(ChanName chan<- int){ ... }

其中 <-chan 和 chan <- 均为单向管道。如果向读管道写入数据或 者从写管道读取数据时,则会在编译的时候就会报错。

关闭管道

使用 close(ChannelName) 对管道进行关闭。此时会将接收队列中的所有协程结束等待状态,同时给予其nil值。而发送队列中的所有协程也会结束等待状态,但是会产生panic。
此外,关闭关闭的管道,关闭值为nil的管道以及向已经关闭的管道写入数据都会产生panic。

有缓冲区管道与无缓冲区管道的区别

声明管道

make(chan type)//无缓冲区
make(chan type,size)//有缓冲区

首先先要说向管道读写操作的流程。

操作说明
有缓冲区写操作发送端首先检查接收队列,如果接收队列不为空,表示buffer中没有数据,发送端可直接取接收队列中的一个协程,将数据写给该协程并将其唤醒。如果接收队列为空,则需要判断buffer中是否已满,如果已满的话,该发送端则进入发送队列,进入等待状态。未满则直接将数据写入buffer中,结束写的操作。
无缓冲区写操作由于没有缓冲区发送端直接检查接收队列,如果接收队列为空,则将进入发送队列中,进入等待状态。如果接收队列不为空,则直接将数据写给接收队列中的协程,并将其唤醒。
有缓冲区读操作接收端首先检查发送队列,如果发送队列为空,则检查buffer。如果buffer为空,则该协程进入接收队列,并陷入等待状态。如果buffer中有数据,则读取buffer的首部数据。如果发送队列不为空,则读取buffer队列中的首部的数据,并将接发送队列中的首个协程的数据写到buffer的尾部,该进程被唤醒。
无缓冲区读操作接收端检查发送队列,如果发送队列为空,则将该协程添加至等待队列尾部。如果发送队列不为空,则取发送队列的队首数据,并使其退出等待状态。

由此可见无缓冲区的情况是有缓冲区的变种情况。
那么有无缓冲区到底有什么实质的影响呢?看一下的代码可能就会发现其中的问题。

func main(){  
	ch := make(chan int)//无缓冲区  
	tag := sync.WaitGroup{}  
  	tag.Add(1)  
  	go func(){  
   		ch <- 1  
 		fmt.Println("Send Finish")  
    	tag.Done()  
  	}()  
 	tag.Wait()  
  	fmt.Println(<-ch)  
}
func main(){  
	ch := make(chan int,1) //有缓冲区
	tag := sync.WaitGroup{}  
  	tag.Add(1)  
  	go func(){  
   		ch <- 1  
 		fmt.Println("Send Finish")  
    	tag.Done()  
  	}()  
  	tag.Wait()  
  	fmt.Println(<-ch)  
}

通过运行结果,可以发现无缓冲区的程序产生死锁。原因为无缓冲区时,写操作需要等待读操作使其退出等待状态,但是在该程序中,由于该协程需要等待一个读操作而主进程又在等待该协程的结束,导致死锁。这时应使用有缓冲区的管道解决该死锁的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值