Channel

本文深入探讨了Go语言中的管道机制,包括无缓冲和带缓冲管道的使用,详细阐述了读写操作的阻塞条件以及管道的数据结构。通过管道,协程间实现了高效的数据通信和并发控制。关闭管道的行为及其可能引发的panic情况也进行了说明。
摘要由CSDN通过智能技术生成

Channel

  • 管道是Go在语言层面提供的协程间的通信方式。

  • 管道有无缓冲管道和带缓冲管道

    ch1 := make(chan string)		//无缓冲
    ch2 := make(chan string, 5)		//有缓冲
    
  • 数据读写

    1. 无缓冲:从管道中读写数据会被阻塞,直到有协程向管道中写或读数据。
    2. 有缓冲:有缓冲但缓冲为空的Chan读取数据时也会被阻塞,直到有协程写入数据;有缓冲但缓冲已满的Chan中写数据时也会被阻塞,直到有协程读取数据。
    3. 对于值为nil的Chan,无论读写都会阻塞,而且是永久阻塞。
  • 阻塞的条件:

    1. 协程读取管道时,阻塞的条件有:

      管道无缓冲区 管道缓冲区为空 管道的值为nil

    2. 协程写入管道时,阻塞的条件有:

      管道无缓冲区 管道缓冲区已满 管道的值为nil

  • 管道的数据结构

    type hchan struct{				//环形队列
        qcount uint					//当前队列中剩余元素的个数  len(ch1)
        dataqsiz uint				//环形队列长度,即cap(ch1)
        buf	unsafe.Pointer			//环形队列指针
        elemsize uint16				//每个元素的大小
        closed	uint32				//标识关闭状态
        elemtype *_type				//元素类型
        sendx	uint				//队列下标,元素写入时存放到队列中的位置
        recvx	uint				//队列下标,下一个被读取的元素在队列中的位置
        recvq	waitq				//等待读消息的协程队列
        sendq	waitq				//等待写消息的协程队列
        lock	mutex				//互斥锁,chan不允许并发读写
    }
    
  • 管道的读写操作

    • 向管道中写数据

      • 如果缓冲区有空余位置,将数据写入缓冲区中,结束发送进程
      • 如果缓冲区中没有空余位置,将当前协程加入senq队列,进入睡眠并等待被唤醒。

      注意:上面形容缓冲区时,用是否有空余位置来形容,是因为存在着无缓冲区的chan

      在实现时,当接收队列recvq不为空,说明缓冲区中没有数据,但是有协程在等待读数据,此时会把数据直接传递给recvq队列中的第一个协程,而不必在写入缓冲区。

    • 从管道中读数据

      • 如果缓冲区中有数据,则从缓冲区中读数据,结束读取进程
      • 如果缓冲区中无数据,则将当前协程加入recvq队列,进入睡眠并等待被写协程唤醒

      在实现时,如果等待发送队列sendq不为空,且没有缓冲区,那么此时将直接从sendq队列的第一个协程获取数据。

    • 关闭管道

      关闭管道时会把recvq中的协程全部唤醒,这些协程获取数据都为对应类型的零值;同时会把sendq队列中的携程全部唤醒,但这些协程都会触发panic;

      除此之外,还存在一些其他触发panic的操作

      • 关闭值为nil的管道
      • 关闭已经关闭的管道
      • 向已经被关闭的管道发送数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值