博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go-channel的关闭和广播
阅读量:2211 次
发布时间:2019-04-29

本文共 3061 字,大约阅读时间需要 10 分钟。

目录


一、不关闭channel会怎样

我们先写一个数据生产者和数据消费者的程序,数据生产者不断生成数据,消费者不断消费生产者生产的数据。

package channel_closeimport (	"fmt"	"sync"	"testing")//数据生产者func dataProducer(ch chan int, wg *sync.WaitGroup) chan int {	wg.Add(1)	go func() {		for i := 0; i < 10; i++ {			ch <- i		}		wg.Done()	}()	return ch}//数据消费者func dataConsumer(ch chan int, wg *sync.WaitGroup) {	wg.Add(1)	go func() {		for i := 0; i < 10; i++ {			data := <-ch			fmt.Println(data)		}		wg.Done()	}()}//数据消费者func dataConsumer2(ch chan int, wg *sync.WaitGroup) {	wg.Add(1)	go func() {		for i := 0; i < 10; i++ {			data := <-ch			fmt.Println(data)		}		wg.Done()	}()}//channel还未关闭的场景func TestChannelNotClosed(t *testing.T) {	ch := make(chan int)	var wg sync.WaitGroup	dataProducer(ch, &wg)	dataConsumer(ch, &wg)	wg.Wait()}

一旦我们生产的数据和消费的数据不一致时,比如生产者可以生成 11 个数,消费者仍然只消费 10 个数,或者生产者生成 10 个数,而消费者去消费 11 个数时,就会报下面的错误:

fatal error: all goroutines are asleep - deadlock!

为了解决这种问题,Go 急需 channel 具有关闭功能,且关闭后会广播所有的订阅者。

二、channel 的关闭

1、语法格式

//关闭 channelclose(channelName)//ok=true表示正常接收,false表示通道关闭if val, ok := <-ch; ok {    //other code}

2、channel关闭的特点

  • 关闭的 channel 发送数据,会导致 panic
  • ok为bool值,true 表示正常接受,false 表示通道关闭
  • 所有的 channel 接收者都会在 channel 关闭时,立刻从阻塞等待中返回且 ok 值为 false。这个广播机制常被利用,进行向多个订阅者同时发送信号。如:退出信号。

3、接收已关闭 channel 的值

当 channel 已正常关闭,数据接收者还继续接收数据,则接收的数据为 channel 对应数据的默认值

package channel_closeimport (	"fmt"	"sync"	"testing")//数据生产者func dataProducer(ch chan int, wg *sync.WaitGroup) chan int {	wg.Add(1)	go func() {		for i := 0; i < 10; i++ {			ch <- i		}        //关闭 channel		close(ch)		//向关闭的 channel 发送消息,会报 panic: send on closed channel		//ch <- 11		wg.Done()	}()	return ch}//数据消费者func dataReceiver(ch chan int, wg *sync.WaitGroup) {	wg.Add(1)	go func() {        //我们这里多接收一个数据,看看拿到的值是什么		for i := 0; i < 11; i++ {			data := <-ch			fmt.Println(data)		}		wg.Done()	}()}//关闭掉 channelfunc TestCloseChannel(t *testing.T) {	ch := make(chan int)	var wg sync.WaitGroup	dataProducer(ch, &wg)	dataReceiver(ch, &wg)	wg.Wait()}/*=== RUN   TestCloseChannel01234567890    --- PASS: TestCloseChannel (0.00s)PASS*/

我们会发现,当 channel 已关闭后,我们多接收了一个值,由于我们 channel 定义的数据类型为 int,则拿到的数据类型讲师 int 型的默认值 0。

4、标准 channel 格式

package channel_closeimport (	"fmt"	"sync"	"testing")//数据生产者func dataProducer(ch chan int, wg *sync.WaitGroup) chan int {	wg.Add(1)	go func() {		for i := 0; i < 10; i++ {			ch <- i		}		//关闭 channel		close(ch)		wg.Done()	}()	return ch}//数据消费者func dataConsumer(ch chan int, wg *sync.WaitGroup) {	wg.Add(1)	go func() {		for {			if data, ok := <-ch; ok {				fmt.Println(data)			} else {				break;			}		}		wg.Done()	}()}//数据消费者func dataReceiver(ch chan int, wg *sync.WaitGroup) {	wg.Add(1)	go func() {		for {			if data, ok := <-ch; ok {				fmt.Println(data)			} else {                //通道关闭后就退出				break;			}		}		wg.Done()	}()}//关闭掉 channelfunc TestCloseChannel(t *testing.T) {	ch := make(chan int)	var wg sync.WaitGroup	//1个数据生成者	dataProducer(ch, &wg)	//多个数据消费者	dataReceiver(ch, &wg)	dataConsumer(ch, &wg)	wg.Wait()}/*=== RUN   TestCloseChannel0123456789--- PASS: TestCloseChannel (0.00s)PASS*/

:这篇博文是我学习中的总结,如有转载请注明出处:

上一篇

下一篇

你可能感兴趣的文章
tomcat连接超时
查看>>
谈谈编程思想
查看>>
iOS MapKit导航及地理转码辅助类
查看>>
检测iOS的网络可用性并打开网络设置
查看>>
简单封装FMDB操作sqlite的模板
查看>>
iOS开发中Instruments的用法
查看>>
iOS常用宏定义
查看>>
什么是ActiveRecord
查看>>
有道词典for mac在Mac OS X 10.9不能取词
查看>>
关于“团队建设”的反思
查看>>
利用jekyll在github中搭建博客
查看>>
Windows7中IIS简单安装与配置(详细图解)
查看>>
linux基本命令
查看>>
BlockQueue 生产消费 不需要判断阻塞唤醒条件
查看>>
强引用 软引用 弱引用 虚引用
查看>>
数据类型 java转换
查看>>
"NetworkError: 400 Bad Request - http://172.16.47.117:8088/rhip/**/####t/approval?date=976
查看>>
mybatis 根据 数据库表 自动生成 实体
查看>>
win10将IE11兼容ie10
查看>>
checkbox设置字体颜色
查看>>