golang channel
channel类型:
- 读写方式上来看,有以下三种:
- 可读可写;
- 仅可写;
- 仅可读;
- 使用情况来看,分为传输的数据类型和是否有缓冲两种情况:
- 传输的数据类型:
channel理论上可以传输任意的数据类型,根据声明时指定的数据类型,传输对应的数据,如chan int就是表示可读写int类型数据的channel; - 无缓冲channel(同步channel):
实际就是同步channel,向无缓冲channel写入数据时,如果没有消费者取出数据,则在写入这个时机就阻塞住了,这里要明确一点,此时数据并没有真正写入通道,只有当有消费者来取数据时,才会把数据传递过去。类似于邮递员送信到你家,你不在家,邮递员不会走,当你收下信,邮递员才离开。同理,消费者端也是一样,从无缓冲通道获取数据时,如果此时生产者还没有写入数据,消费者端也是阻塞住的; - 有缓冲channel(异步channel):
有缓冲通道实际就是在无缓冲通道的基础上增加了一个缓冲区,可以把无缓冲通道看成缓冲区为0,当生产者往有缓冲通道写入数据时,不会阻塞住,数据会放入缓冲区,等待消费者获取,生产者可以往下继续执行,但是缓冲区也是有大小的,这个大小是创建channel时指定的,如果消费者端一直没有取出数据,或者是取出数据的速度没有生产者生产数据的速度快,则缓冲区达到上限后,生产者此时也会阻塞住,无法将数据写入通道,只有消费者从通道取走数据,生产者才可以继续写入,消费者从有缓冲通道获取数据时,如果通道没有数据,则会阻塞住,直到通道有数据可取。
- 传输的数据类型:
附:
调用close方法可以关闭channel,如果向一个已经关闭的channel写数据会引发panic,从一个已经关闭的channel读取数据不会引发panic,如果读取的是一个已关闭的无缓冲channel则读取到的是对应通道数据类型的零值,例如chan int,读取到的数据就是0,如果读取的是已关闭的有缓冲channel,这里就要看有缓冲channel里面是否有未取完的数据,如果有,则会先取出未读完的数据,后续再取则也是零值,所以这里可以用golang提供的多返回值方式来判断是否从通道获取到数据:
i, ok := <- ch
ok为true时,代表从通道取到了数据,i就是获取到的数据。
channel底层也是借助的同步锁机制实现的,再加上channel还需要做很多额外的数据处理,所以有些场景下直接采用sync.Mutex或者sync.WaitGroup性能会更好。