详解go语言判断管道是否关闭的常见误区

 更新时间:2023年10月09日 10:29:42   作者:林欣快滚去学习  
这篇文章主要想和大家一起探讨一下在Go语言中,我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭,文中的示例代码讲解详细,有兴趣的可以了解下

前言

本文是探讨的是"在Go语言中,我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭?"

样例

在Go语言中,我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭? 可以看下面的代码

package main
import "fmt"
func main() {
    // 创建一个整型管道
    ch := make(chan int)
    // 启动一个协程往管道发送数据
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
        }
        // 关闭管道
        close(ch)
    }()
    // 能否判断管道是否关闭?
    if _, ok := <-ch; !ok {
        fmt.Println("管道已关闭")
    }
}

探讨 管道的数据结构

在探讨这个问题之前,我们先来了解一下管道的数据结构,从go的源码,我们可以知道,管道是被定义为一个名为hchan的结构体:

type hchan struct {
    qcount   uint           //当前队列中剩余的元素个数
    dataqsiz uint           // 环形队列管道容积
    buf      unsafe.Pointer // 环形队列指针
    elemsize uint16         // 元素大小
    closed   uint32         // 标识管道关闭的状态
    elemtype *_type         // 元素类型
    recvq    waitq          // 等待的读元素的协程队列
    sendq    waitq          // 等待的写元素的协程队列
    ... 
}

其中,有一个属性是我们应该关注的,那就是closed,这玩意标识了管道是否关闭,这玩意为1代表关闭了,为0代表是开启的.

详细分析

好的,接下来我们继续本文探讨的问题在Go语言中,我们是否可以使用管道的第二个返回值来判断管道是否关闭?先给出结论 : 从严格意义上来讲是不可以的,其实表示是否成功读取数据,但是在缓存区为0的时候,ok的状态和管道状态是一致的,所以会被误认为,这个ok是代表管道的状态可以看下面的例子

package main
import (
   "fmt"
   "time"
)
func main() {
   a2 := make(chan int, 2)
   go demo(a2)
   value2, ok2 := <-a2
   fmt.Printf("value2:%v,ok2:%v\n", value2, ok2)
   time.Sleep(3 * time.Second)
   value3, ok3 := <-a2
   fmt.Printf("value3:%v,ok3:%v\n", value3, ok3)
}
func demo(a chan int) {
   defer func() {
      close(a)
      fmt.Println("管道已经关闭")
   }()
   a <- 1
   a <- 2
}

解释一下运行流程

1.首先创建了一个缓存区为2的管道a2

2.然后用go关键字

将demo函数开辟出一个新的协程运行,此时demo和main是同一级的关系,同时运行,此时main函数会继续向下执行,发现是从管道中读取一个元素,然后就会等待demo函数会向管道中传入值,demo函数的运行过程是这样的,它发现管道a2的缓存是2,所以刚好把元素存入,然后就执行关闭管道,然后demo协程销毁

3.main函数继续执行,接收到a2管道的一个元素之后,然后返回value2和ok2,然后进行打印

4.然后休眠3秒钟

5.然后继续读取a2管道的元素,得到value3和ok3,然后打印

ok2和ok3都为true

’ 管道已经关闭 ’ 这是最先打印的,无论运行多少次,都是一样的,而且我还特地将main函数暂停了3秒,所以我可以保证demo函数已经执行完毕,demo协程已经销毁,然后再执行的第二个管道的数据的读取

逐步调试

那我们调试一下,可以发现,执行了make函数创建管道之后,管道没有关闭,我前面特意提了管道的数据结构,其中closed是标识管道是否关闭的

继续调试,我们可以发现,在读取完管道a2的第一个值赋值给value2和ok2的时候,此时通道已经关闭

value2的值为1,ok2为true

继续调试,通道还是关闭状态,但是ok3的值还是true,看下面的第二张图

所以读取管道元素传来的第二个值,并不是代表管道是否关闭!

那它代表什么?

其实是代表读取数据是否成功,或者说代表缓存区是否还有数据

首先我们要知道, 关闭了的管道, 我们还是可以进行读取的, 这个设定是因为有缓存的存在, 但是如果管道关闭了的话,又没有值,读取的话,会是类型的默认值和false,也就是读取未成功

当然如果是缓存区为0的情况,ok的值和管道的状态是一致的

var c = make(chan int)
close(c)
value, ok := <-c
fmt.Printf("value:%v \nok:%v \n", value, ok)

运行结果:

以上就是详解go语言判断管道是否关闭的常见误区的详细内容,更多关于go判断管道是否关闭的资料请关注脚本之家其它相关文章!

相关文章

  • go使用SQLX操作MySQL数据库的教程详解

    go使用SQLX操作MySQL数据库的教程详解

    sqlx 是 Go 语言中一个流行的操作数据库的第三方包,它提供了对 Go 标准库 database/sql 的扩展,简化了操作数据库的步骤,下面我们就来学习一下go如何使用SQLX实现MySQL数据库的一些基本操作吧
    2023-11-11
  • 一文带你搞懂go中的请求超时控制

    一文带你搞懂go中的请求超时控制

    在日常开发中,对于RPC、HTTP调用设置超时时间是非常重要的,这就需要我们设置超时控制,本文将通过相关示例为大家深入介绍一下go中的请求超时控制,希望对大家有所帮助
    2023-11-11
  • Go语言使用时会遇到的错误及解决方法详解

    Go语言使用时会遇到的错误及解决方法详解

    这篇文章主要为大家详细介绍了Go语言使用时常常会遇到的一些错误及解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-07-07
  • 使用Go重构流式日志网关的实战分享

    使用Go重构流式日志网关的实战分享

    流式日志网关的主要功能是提供 HTTP 接口,接收 CDN 边缘节点上报的各类日志(访问日志/报错日志/计费日志等),将日志作预处理并分流到多个的 Kafka 集群和 Topic 中,本文就给大家分享如何使用 Go 重构流式日志网关
    2023-06-06
  • golang代码检测工具之goimports解读

    golang代码检测工具之goimports解读

    这篇文章主要介绍了golang代码检测工具之goimports使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 浅谈go 协程的使用陷阱

    浅谈go 协程的使用陷阱

    这篇文章主要介绍了浅谈go 协程的使用陷阱,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go Error 嵌套实现创建方式

    Go Error 嵌套实现创建方式

    这篇文章主要介绍了Go Error 嵌套到底是怎么实现的?大家都知道创建error有两种方式分别是errors.new()另一种是fmt.errorf(),本文通过详细例子给大家介绍,需要的朋友可以参考下
    2022-01-01
  • 深入解析Go语言的io.ioutil标准库使用

    深入解析Go语言的io.ioutil标准库使用

    这篇文章主要介绍了Go语言的io.ioutil标准库使用,是Golang入门学习中的基础知识,需要的朋友可以参考下
    2015-10-10
  • Golang通脉之类型定义

    Golang通脉之类型定义

    这篇文章主要介绍了Golang通脉之类型定义,在Go语言中有一些基本的数据类型,如 string 、 整型 、 浮点型 、 布尔 等数据类型, Go语言中可以使用 type 关键字来定义自定义类型,下面和小编一起进入文章看具体内容吧
    2021-10-10
  • go语言之给定英语文章统计单词数量(go语言小练习)

    go语言之给定英语文章统计单词数量(go语言小练习)

    这篇文章给大家分享go语言小练习给定英语文章统计单词数量,实现思路大概是利用go语言的map类型,以每个单词作为关键字存储数量信息,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2020-01-01

最新评论