理解golang中关键字-chan&select

chan

channel直译过来就是管道,chan关键字定义了goroutine中的管道通信,一个goroutine可以和另一个goroutine进行通信。

chan的读写和定义如下:

//define a chan type variable
var ch chan int = make(chan int, 10);
//or
ch := make(chan int, 10);

//write data into chan 
ch <- 1;
ch <- 2;

//read data from chan 
var x int;
x = <-ch;
x = <-ch;

看下面这段代码,其中x获取ch队头值,nonempty返回ch是否非空的:

func main() {
	var ch chan int = make(chan int, 10)
	ch <- 1
	ch <- 2
	ch <- 3
	close(ch)

	var x int
	var nonempty bool
	x, nonempty = <-ch
	fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
	x, nonempty = <-ch
	fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
	x, nonempty = <-ch
	fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
  x, nonempty = <-ch
	fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
}

打印结果:

可以看到chan是类似队列的先进先出类型,每次读出一个数据后,ch自动弹出该数据不再保存。

chan一定要初始化才能进行读写操作,否则产生死锁:

package main

import (
	"fmt"
)

func main() {
	var ch chan int// = make(chan int, 10)
	ch <- 1
	ch <- 2
	ch <- 3
	close(ch)

	var x int
	var nonempty bool
	x, nonempty = <-ch
	fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
	x, nonempty = <-ch
	fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
	x, nonempty = <-ch
	fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
      x, nonempty = <-ch
	fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
}

执行结果,由于所有goroutine已经睡眠,产生死锁: 

select

select会执行第一个可以执行的case语句,会一直监听直到有第一个可以执行的语句。或者换一种说法,select就是用来监听和channel有关的IO操作,当 IO 操作发生时,触发相应的动作。

看这段代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	var ch chan int = make(chan int, 10)
	var x int = 0
	var nonempty bool

	go func() {
		ch <- 1
		ch <- 2
		ch <- 3
		close(ch)
		x, nonempty = <-ch
		fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
		x, nonempty = <-ch
		fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
		x, nonempty = <-ch
		fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
		x, nonempty = <-ch
		fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
	}()
	select {
	case ch <- x:
		fmt.Println("ch write", x)
	case x = <-ch:
		fmt.Println("ch read", x)
	default:
		fmt.Println("nothing to do")
	}
	time.Sleep(time.Second)
}

执行结果,写入0:

注释掉第一个case:

	select {
	// case ch <- x:
	// 	fmt.Println("ch write", x)
	case x = <-ch:
		fmt.Println("ch read", x)
	default:
		fmt.Println("nothing to do")
	}

 执行结果,由于ch为空无法读出,运行default:

如果有多个io操作都可以执行的话,select会随机选择一个执行:

	select {
	// case ch <- x:
	// 	fmt.Println("ch write", x)
	case ch <- 4:
		fmt.Println("ch write 4")
	case ch <- 5:
		fmt.Println("ch write 5")
	case x = <-ch:
		fmt.Println("ch read", x)
	default:
		fmt.Println("nothing to do")
	}

两种结果:

                    

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值