Go语言Channel理解使用

首先我是从一个指导中看到一段话才想要来写这篇文章的,主要是一段容易让人误解的话,这里我直接把他的代码附上。也可以先看一些基础知识:

目录

基础

误解代码

修改代码和结果对比


基础

作用:用于在协程之间传递信息

类型:通道是引用类型,规则和切片相似,需要make

定义方式和操作:

var ch chan int//最后一个标识通道传递的元素类型
make(chan 元素类型, [缓冲大小])
ch <- n //写
n <- ch //读
close(ch)//关闭

误解代码

代码的核心是两个线程以及连个无缓冲的通道。误会主要发生在下面的依据注释中**通道关闭后再取值ok=false**,对于他设置的无缓冲通道交换信息来说,可以是对的,但如果是有缓冲通道,则是明显的错误。下面我附上稍微修改的代码,二者对比就可明白。

package main
//代码一
import (
    "fmt"
	//"time"
)
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    // 开启goroutine将0~100的数发送到ch1中
    go func() {
        for i := 0; i < 100; i++ {
            ch1 <- i
        }
        close(ch1)
     
    }()
    // 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中

    go func() {
        for {
            i, ok := <-ch1 // **通道关闭后再取值ok=false**
            if !ok {
                break
            }
            ch2 <- i * i
        }
		close(ch2)

    }()
    // 在主goroutine中从ch2中接收值打印
    for i := range ch2 { // 通道关闭后会退出for range循环
        fmt.Println(i)
	
    }
}

这是稍微修改的代码,可以看到修改了两处,溢出时把通道1换成了带缓冲的,一处时把关闭通道1的时刻换到i=50的时候,我们对比一下二者的执行结果:

修改代码和结果对比

package main

import (
    "fmt"
	//"time"
)
func main() {
    ch1 := make(chan int,100)//改成了有缓冲的通道
    ch2 := make(chan int)
    // 开启goroutine将0~100的数发送到ch1中
    go func() {
        for i := 0; i < 100; i++ {
            ch1 <- i
        }
     
    }()
    // 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中

    go func() {
        for {
            i, ok := <-ch1 // 通道关闭后再取值ok=false
            if !ok {
                break
            }
            //修改处
			if i == 50{
				close(ch1)
			}
		
            ch2 <- i * i
        }
		close(ch2)

    }()
    // 在主goroutine中从ch2中接收值打印
    for i := range ch2 { // 通道关闭后会退出for range循环
        fmt.Println(i)
	
    }
}

可以看到,虽然提前关闭了通道,但是因为有缓冲区的缘故,字符都是正常取出的,因为

 i, ok := <-ch1 只要通道里有值存在返回的就是ok。关闭后虽然无法添加数据,但是通道取值是正常的,只有当元素被取完后才会返回false。其实他这么说能行得通的原因是无缓冲通道的原因,接受通道会一直阻塞知道发送方传值,通道中是不存有元素的。因此如果没有接收,不可以向一个无缓冲通道添加值。

单向通道

有的时候我们会将通道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中使用通道都会对其进行限制,比如限制通道在函数中只能发送或只能接收。

Go语言中提供了单向通道来处理这种情况:

可以在函数传参及任何赋值操作中将双向通道转换为单向通道。

package main

import "fmt"
//写通道
func counter(out chan<- int) {
    for i := 0; i < 100; i++ {
        out <- i
    }
    close(out)
}

func squarer(out chan<- int, in <-chan int) {
    for i := range in {
        out <- i * i
    }
    close(out)
}
//读通道
func printer(in <-chan int) {
    for i := range in {
        fmt.Println(i)
    }
}

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go counter(ch1)
    go squarer(ch2, ch1)
    printer(ch2)
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值