go中的Channel (总结于尚硅谷go)

Channel

​ channel是一个数据类型,主要用来解决协程的同步问题以及协程之间数据共享(数据传递)的问题。可以把它看成管道,一端读,一端写

goroutine运行在相同的地址空间,因此访问共享内存必须做好同步 goroutine 奉行通过通信来共享内存,而不是共享内存来通信。引⽤类型 channel可用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。
在这里插入图片描述

定义channel的变量方式
make(chan Type)  //等价于make(chan Type, 0)
make(chan Type, capacity)
channel的操作方式
channel <- value  //写到channel里面
<- channel        //从channel中读出        x := <-channel  //从channel读出来赋值给x

默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得goroutine同步变的更加的简单,而不需要显式的lock

    c := make(chan int)
    go func() {
        defer fmt.Println("子协程结束")

        fmt.Println("子协程正在运行……")

        c <- 666 //666发送到c
    }()
    num := <-c //从c中接收数据,并赋值给num
    fmt.Println("num = ", num)
    fmt.Println("main协程结束")
无缓冲区Channel:

​ 不会保存接受到的值

	ch := make(chan int)
	go func() {
		for i:=0;i<5 ;i++  {
			fmt.Println("Sub go i Write: " ,i)
			ch <- i
		}
	}()

	for i:=0;i<5 ;i++  {
		num := <- ch
		fmt.Println("Main go read i :", num)
	}
}
有缓冲区Channel:

会保存接受到的值

	ch := make(chan int ,5)  //存满5元素之前不会堵塞
	fmt.Println(len(ch))
	fmt.Println(cap(ch))

	go func() {
		for i := 0;i<10;i++ {
			ch <- i
			len:= len(ch)
			cap:= cap(ch)
			fmt.Println("Sub go : ", " len: ",len, " cap: ", cap)
			//fmt.Println(i)
		}
	}()
	time.Sleep(time.Second *5)
	for i:= 0 ;i< 8 ;i++  {
		num := <-ch
		fmt.Println("Main go : " ,num)
	}


input//
Sub go :   len:  1  cap:  5
Sub go :   len:  2  cap:  5
Sub go :   len:  3  cap:  5
Sub go :   len:  4  cap:  5
Sub go :   len:  5  cap:  5
Main go :  0
Main go :  1
Main go :  2
Main go :  3
Main go :  4
Main go :  5 
Sub go :   len:  5  cap:  5    // 输出的多了 是因为io操作的延迟所导致的
Sub go :   len:  0  cap:  5
Sub go :   len:  1  cap:  5
Sub go :   len:  2  cap:  5
Sub go :   len:  3  cap:  5
Main go :  6
Main go :  7

关闭Channel

如果发送者知道,没有更多的值需要发送到channel的话,那么让接收者也能及时知道没有多余的值可接收将是有用的,因为接收者可以停止不必要的接收等待。这可以通过内置的close函数来关闭channel实现。

	ch := make(chan int)
	
	go func() {
		for i:= 0;i<5 ;i++  {
			 ch <- i
		}
		close(ch)
	}()

	for  {
		if num,flag := <- ch;flag == true {
			fmt.Println("Channel Read data :" ,num)
		}else {
			break
		}
	}

l 关闭channel后,无法向channel 再发送数据(引发 panic 错误后导致接收立即返回零值);

l 关闭channel后,可以继续从channel接收数据;

可以使用range来迭代不断操作channel

    c := make(chan int)

    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        //把 close(c) 注释掉,程序会一直阻塞在 for data := range c 那一行
        close(c)
    }()

    for data := range c {
        fmt.Println(data)
    }
    fmt.Println("Finished")
单向channel

默认情况下,通道channel是双向的,也就是,既可以往里面发送数据也可以同里面接收数据。

但是,我们经常见一个通道作为参数进行传递而值希望对方是单向使用的,要么只让它发送数据,要么只让它接收数据,这时候我们可以指定通道的方向。

声明方式:

var ch1 chan int       // ch1是一个正常的channel,是双向的
var ch2 chan<- float64 // ch2是单向channel,只用于写float64数据
var ch3 <-chan int     // ch3是单向channel,只用于读int数据


chan<- //表示数据进入管道,要把数据写进管道,对于调用者就是输出。
<-chan //表示数据从管道出来,对于调用者就是得到管道的数据,当然就是输入。

可以将 channel 隐式转换为单向队列,只收或只发,不能将单向 channel 转换为普通 channel

	ch := make(chan int)
	var WriteCh chan <- int = ch
	WriteCh <- 123

	var ReadCh <- chan int = ch
	num := <-ReadCh
	fmt.Println(num)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值