Channel管道的基础

Channel管道的基础(一)

func main(){
    ch := make(chan interface{})		// 无缓冲管道
   对于没有缓存的通道,需要接收方实时接收数据,否则会报错
    ch1 := make(chan interface{}, 10)		// 带缓冲区的管道
    
    // 向管道发送数据
    ch1 <- struct{}
    ch1 <- 0
    ch1 <- "hello"
    select{			// 专门用来选择管道的功能
        case cd <- struct{}{}:
        default :
    }	
}

阻塞接收数据

date := <-ch1

非阻塞接收数据

data, ok := <-ch1

data:表示接收的数据信息
ok:表示是否接收到该数据接收任何数据<-ch1

原理解析

func main(){
    ch := make(chan interface{},1)
    ch <- 0
}
go tool compile -N -l -S main.go 

初始化方法实际上调用的就是 runtime.makechan方法,返回一个指针,来操作管道结构里面的值来操作数据

func makechan(t *chantype, size int) *hchan {
	elem := t.elem

	// compiler checks this but be safe.
	if elem.size >= 1<<16 {
		throw("makechan: invalid channel element type")
	}
	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
		throw("makechan: bad alignment")
	}

	mem, overflow := math.MulUintptr(elem.size, uintptr(size))
	if overflow || mem > maxAlloc-hchanSize || size < 0 {
		panic(plainError("makechan: size out of range"))
	}

	// Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers.
	// buf points into the same allocation, elemtype is persistent.
	// SudoG's are referenced from their owning thread so they can't be collected.
	// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
	var c *hchan
	switch {
	case mem == 0:
		// Queue or element size is zero.
		c = (*hchan)(mallocgc(hchanSize, nil, true))
		// Race detector uses this location for synchronization.
		c.buf = c.raceaddr()
	case elem.ptrdata == 0:
		// Elements do not contain pointers.
		// Allocate hchan and buf in one call.
		c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
		c.buf = add(unsafe.Pointer(c), hchanSize)
	default:
		// Elements contain pointers.
		c = new(hchan)
		c.buf = mallocgc(mem, elem, true)
	}

	c.elemsize = uint16(elem.size)
	c.elemtype = elem
	c.dataqsiz = uint(size)
	lockInit(&c.lock, lockRankHchan)

	if debugChan {
		print("makechan: chan=", c, "; elemsize=", elem.size, "; dataqsiz=", size, "\n")
	}
	return c
}

1、如果创建一个无缓冲channel ,那么只需要为runtime.hchan本身分配一段内存空间即可。
2、如果创建的缓冲channel存储的类型不是指针类型,会为当前channel和存储类型元素的缓冲区,分配一块连续的内存空间。
3、在默认情况下(缓冲channel存储类型包含指针),会单独为runtime.hchan和缓冲区分配内存。

type hchan struct {
	qcount   uint           // total data in the queue 队列中元素总数量
	dataqsiz uint           // size of the circular queue	队列容量
	buf      unsafe.Pointer // points to an array of dataqsiz elements	元素数据内存buffer区域
	elemsize uint16		// 队列中每个对象的大小
	closed   uint32		// channel是否关闭
	elemtype *_type // element type		 队列中元素的类型
	sendx    uint   // send index		 发送位置索引
	recvx    uint   // receive index	接收位置索引
	recvq    waitq  // list of recv waiters		等待读消息的g队列
	sendq    waitq  // list of send waiters		等待发消息的g队列

	// lock protects all fields in hchan, as well as several
	// fields in sudogs blocked on this channel.
	//
	// Do not change another G's status while holding this lock
	// (in particular, do not ready a G), as this can deadlock
	// with stack shrinking.
	lock mutex		// 互斥锁
}

本质:创建一个channel就是得到一个runtime.hchan的指针,后续对此chan的操作,无非就是对该结构体中的相应字段进行操作。

保持并发的原因:channel内部使用了互斥锁来保证了并发安全若有收获

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值