select_channel以及channel关闭问题

目录

select定义:

一.select应用

二.select_channel遇到的死锁问题

三.select的随机选取

四.如何判断通道是否关闭

五.对已关闭的通道进行写值

六.对已关闭的通道进行读值


select定义:

   select 语句用于在多个发送/接收信道操作中进行选择。select 语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。该语法与 switch 类似,所不同的是,这里的每个 case 语句都是信道操作。

         注:select 最好是带有default,这样避免信道没有返回响应(一直没有信息输出)而导致堵塞,会造成死锁。

一.select应用

select的实际应用含义如下: 
    假设我们有一个关键性应用,需要尽快地把输出返回给用户。这个应用的数据库复制并且存储在世界各地的服务器上。假设函数 server1 和 server2 与这样不同区域的两台服务器进行通信。每台服务器的负载和网络时延决定了它的响应时间。我们向两台服务器发送请求,并使用 select 语句等待相应的信道发出响应。select 会选择首先响应的服务器,而忽略其它的响应。使用这种方法,我们可以向多个服务器发送请求,并给用户返回最快的响应了

    //demo1
	ch1 := make(chan string)
	ch2 := make(chan string)
	go server1(ch1)
	go server2(ch2)
	for {
		time.Sleep(time.Millisecond * 1000)
		select {
		case s1 := <-ch1:
			fmt.Println(s1)
		case s2 := <-ch2:
			fmt.Println(s2)
		default:
			fmt.Println("nothing server receive")
		}
	}
1.主程序到select-case语句时,这里会发生阻塞。直到其中有case准备就绪,才会进行输出最先准备好的信道信息
2.在没有 case 准备就绪时,可以执行 select 语句中的默认情况(Default Case)。这通常用于防止 select 语句一直阻塞。

二.select_channel遇到的死锁问题

	//1
	ch1 := make(chan string)
	select {
	case s1 := <-ch1:
		fmt.Println(s1)
	default: 
		fmt.Println("nothing server receive")
	}

         1. 这里的第一个demo,如果没有加 default(默认情况),而上面case 试图接受信道中的信息,但却没有人进行向信道发送信息,就会出现死锁问题。

         2.如果select含有值为nil的信道,同样会执行默认情况default。这里的ch1就等于nil,如果没有默认情况default,会一直阻塞,导致死锁


	//2
	select {}

    这里若是没有case执行,则select语句会一直阻塞着,导致死锁

三.select的随机选取

	ch3 := make(chan string)
	ch4 := make(chan string)
	go server3(ch3)
	go server4(ch4)
	time.Sleep(1 * time.Second)
	select {
	case s1 := <-ch3:
		fmt.Println(s1)
	case s2 := <-ch4:
		fmt.Println(s2)
    当select中两个case都准备就绪时,会进行随机输出。若在playground 上在线运行的话,它的输出总是一样的,这是由于 playground 不具有随机性所造成的。

四.如何判断通道是否关闭


	//用select_channel结合就可以解决
	ch := make(chan int, 10)
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
		}
	}()
	time.Sleep(3 * time.Second)
	close(ch)
	for i := 0; i < 10; i++ { //这里不断循环,进行遍历通道里的内容
		select {
		case msg, ok := <-ch:
			if ok {
				fmt.Println(msg)
			} else {
				fmt.Println("channel is closing")
			}
		default:
			fmt.Println("正在等待通道输出信息")
		}
	}

       这里可以通过select_channel结合进行解决,通过close(channel) 内置函数,返回的形式 x,ok:=<-ch,其中通过 ok若为true则通道还未关闭,还在发送数据。若为fasle,则通道已经关闭,无数据发送。

         这里最好是带有default,避免通道堵塞,造成死锁。

五.对已关闭的通道进行写值

c := make(chan int, 2)
close(c)
c <- 1
会出现panic: send on closed channel

六.对已关闭的通道进行读值

c := make(chan int, 2)
	c <- 1
	c <- 2
	close(c)
	value, ok := <-c
	fmt.Println(value, ok)
	value, ok = <-c
	fmt.Println(value, ok)
	value, ok = <-c
	fmt.Println(value, ok)
1.读已经关闭的 chan 能一直读到东西,但是读到的内容根据通道内关闭前是否有元素而不同。
2.如果 chan 关闭前,buffer 内有元素还未读 , 会正确读到 chan 内的值,且返回的第二个 bool 值(是否读成功)为 true。
3.如果 chan 关闭前,buffer 内有元素已经被读完,chan 内无值,接下来所有接收的值都会非阻塞直接返回,返回 channel 元素的零值(如果是string就返回空字符串),但是第二个 bool 值一直为 false。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值