golang怎么判断chan已经关闭

Golang中channel不需要主动close的场景 Golang中,channel不会自动关闭。但某些情况下,可以不手动关闭 channel,而是通过设计让 channel 自然“结束生命周期”(被垃圾回收),而无需显式关闭。 阅读详情

我们都知道data, ok := <- chan第一个变量表示读出的数据,第二个变量表示是否成功读取了数据,有意思的是,第二个变量并不用于指示管道的关闭的状态。第二个变量常常被误以为关闭状态是因为它确实和管道状态有关,确切的来说,是和管道缓冲区是否有数据有关。

如果判断golang的channel是否关闭,data, ok := <- chan,当ok不是true的时候,说明是channel关闭了。 那么问题来了,channel关闭了,我们是否可以立马获取到channel被关闭的状态?我想这个问题不少人没有去想吧?为什么有这样的问题?  来自我的一个bug,我期初认为close了一个channel,消费端的goroutine自然是可以拿到channel的关闭状态。然而事实并不是这样的。 只有当channel无数据,且channel被close了,才会返回ok=false。  所以,只要有堆积,就不会返回关闭状态。导致我的服务花时间来消费堆积,才会退出。

测试channel的关闭状态

package main



import (

    "fmt"

)



func main() {

    c := make(chan int, 10)

    c <- 1

    c <- 2

    c <- 3

    close(c)

    for {

        i,  ok := <-c

        fmt.Println(ok)

        if !ok {

            fmt.Println("channel closed!")

            break

        }

        fmt.Println(i)

    }

}

 

我们发现已经把channel关闭了,只要有堆积的数据,那么ok就不为false,不为关闭的状态。

go runtime channel源码分析

   首先我们来分析下go runtime/chan.go的相关源码,记得先前写过一篇golang channel实现的源码分析,有兴趣的朋友可以翻翻。 这次翻channel源码主要探究下close chan过程及怎么查看channel是否关闭?

   下面是channel的hchan主数据结构,closed字段就是标明是否退出的标识。

type hchan struct {

qcount   uint           // total data in the queue

dataqsiz uint           // size of the circular queue

buf      unsafe.Pointer // points to an array of dataqsiz elements

elemsize uint16

closed   uint32

        ...

}

下面是关闭channel的函数,修改了closed字段为1, 1为退出。

//go:linkname reflect_chanclose reflect.chanclose

func reflect_chanclose(c *hchan) {

closechan(c)

}



func closechan(c *hchan) {

if c == nil {

panic(plainError("close of nil channel"))

}



lock(&c.lock)

if c.closed != 0 {

unlock(&c.lock)

panic(plainError("close of closed channel"))

}

        ....

c.closed = 1

        ...

}

    下面是channel的recv消费者方法,也就是 data, ok := <- chan。if c.closed != 0 && c.qcount == 0 只有当 closed为1 并且 堆积为0的时候,才会返回false。 一句话,channel已经closed,并且没有堆积任务,才会返回关闭channel的状态。

func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {

        ....

lock(&c.lock)



if c.closed != 0 && c.qcount == 0 {

if raceenabled {

raceacquire(unsafe.Pointer(c))

}

unlock(&c.lock)

if ep != nil {

typedmemclr(c.elemtype, ep)

}

return true, false

}



if sg := c.sendq.dequeue(); sg != nil {

recv(c, sg, ep, func() { unlock(&c.lock) }, 3)

return true, true

}



if c.qcount > 0 {

// Receive directly from queue

qp := chanbuf(c, c.recvx)

c.qcount--

unlock(&c.lock)

return true, true

}

   ...

}

channel代码里没有找到一个查询channel关闭的方法。

解决方法

那么如何在channel堆积的情况下,得知channel已经关闭了 ?

第一种方法:

可以直接读取channel结构hchan的closed字段,但问题chan.go没有开放这样的api,所以我们要用reflect这个黑科技了。  (不推荐大家用reflect的方法,因为看起来太黑科技了)

import (

    "unsafe"

    "reflect"

)



func isChanClosed(ch interface{}) bool {

    if reflect.TypeOf(ch).Kind() != reflect.Chan {

        panic("only channels!")

    }

    cptr := *(*uintptr)(unsafe.Pointer(

        unsafe.Pointer(uintptr(unsafe.Pointer(&ch)) + unsafe.Sizeof(uint(0))),

    ))



    // this function will return true if chan.closed > 0

    // see hchan on https://github.com/golang/go/blob/master/src/runtime/chan.go

    // type hchan struct {

    // qcount   uint           // total data in the queue

    // dataqsiz uint           // size of the circular queue

    // buf      unsafe.Pointer // points to an array of dataqsiz elements

    // elemsize uint16

    // closed   uint32

    // **



    cptr += unsafe.Sizeof(uint(0))*2

    cptr += unsafe.Sizeof(unsafe.Pointer(uintptr(0)))

    cptr += unsafe.Sizeof(uint16(0))

    return *(*uint32)(unsafe.Pointer(cptr)) > 0

}

第二种方法:

配合一个context或者一个变量来做。就拿context来说,那么select不仅可以读取数据chan,且同时监听<- context.Done() , 当context.Done()有事件,直接退出就ok了。

 ...

ctx, cancel := context.WithCancel(context.Background())

close(c)

cancel()

exit:

for {

select {

case data, ok := <-c:

fmt.Println(data, ok)



case <-ctx.Done():

break exit

}

}

     ...

 

Channel 源码解读 go中Chan基础知识解读与源码解析 阅读详情

相关推荐

golang判断chan channel是否关闭的方法

主要介绍了golang判断chan channel是否关闭的方法,结合实例形式对比分析了Go语言判断chan没有关闭的后果及关闭的方法,需要的朋友可以参考下

golang判断通道chan是否关闭的2种方式

chan通道在go语言的办法编程中使用频繁,我们可以通过以下2种方式来判断channel通道是否已经关闭,1是使用 for range循环,另外是通过 for循环中if 简短语句的 逗号 ok 模式来判断。

Tekin 是深耕技术 20 年的全栈实战派专家,精通 Go/Python/Java 等多语言开发。博客专注技术原理与实战结合,深度解析 Python 高阶编程、Go 语言架构、数据库优化等硬核内容。涵盖并发编程、机器学习、云原生等前沿领域,通过真实案例拆 2264

【SAP PO】SAP PO 接口配置完整教程之一RFC服务发布

SAP RFC开发,PO接口配置

XLevon的博客 2万+

golang学习之如何判断Channel是否已经关闭【转载】

为什么有这样的问题? 来自我的一个bug,我期初认为close了一个channel,消费端的goroutine自然是可以拿到channel的关闭状态。然而事实并不是这样的。 只有当channel无数据,且channel被close了,才会返回ok=false。 所以,只要有堆积,就不会返回关闭状态。导致我的服务花时间来消费堆积,才会退出。 测试channel的关闭状态 // xiaorui.cc package main import ( "fmt" ) func m...

cyb_17302190874的博客 4165

gtsam 学习十(ISAM2 理论)

翻译自:iSAM2: Incremental Smoothing and Mapping Using the Bayes Tree 摘要 提出了一种新型的贝斯树处理稀疏矩阵,在转化为因子图,可以更好的求解平方根信息和映射问题。 文中提出了三个概念 使用概率密度项进行矩阵分解 介绍如何将矩阵分解转换为贝叶斯数和条件概率密度 基于贝叶斯树提供了一种新的系数非线性优化:ISAM2(进行重新排序和重新线性化,避免了批量更新) 问题描述 文章聚焦与如何用增量实时解决非线性问题, 利用增量即新的测量值实时更新估

weixin_37781153的博客 8407

termux 安装 rockylinux

往找最新的文件目录,选择ARM版本的image。或者直接查看目录或者国内阿里云镜像,按照cpu架构(安卓9手机一般是aarch64arm最新架构),获取镜像地址,以及checksum里的SHA256信息更新到以下rocky9.sh脚本,如果不需要直接使用即可。

欢迎来到别往的博客 983

go 判断channel是否关闭

结论: 1. go语言无法判断channel是否关闭 2. 从channel读取数据,第二个返回值为true时表明:只能证明channel中已没有残留数据且已关闭 3. 若channel已关闭,那么从该channel中读取数据会直接返回,且是默认值 实验如下图: 实验源码如下: package main import ( "fmt" ) func main() { c :=...

papaya的博客 1万+

哨兵一号burst数据的下载和处理

在Sentinel - 1数据处理领域,其基本流程起始于从(ASF)下载原始压缩文件。这些文件规模颇为可观,常规大小约4GB,而部分数据的原文件甚至已攀升至7GB,对存储空间提出了严苛要求。从影像构成来看,每景Sentinel - 1影像由三个干涉宽幅(IW)模式子带组成,每个IW一般包含9个脉冲串(burst)。然而,在实际研究中,我们所关注的研究区域往往仅占据其中寥寥几个burst。

kangkangluoluo的博客 1964

golang判断短chan channel是否关闭

golang判断短chan channel是否关闭 群里有朋友问,怎么判断chan是否关闭,因为close的channel不会阻塞,并返回类型的nil值,会导致死循环.在这里写个例子记录一下,并且分享给大家 如果不判断chan是否关闭 Notice: 以下代码会产生死循环 package main import ( "fmt" ) func main()...

weixin_30692143的博客 214

Excel数据清洗实战:8个必学函数搞定90%的脏数据问题(附案例)

本文通过一个完整的销售数据清洗案例,详细讲解了如何组合使用TRIM、CLEAN、SUBSTITUTE等8个核心Excel函数,构建自动化清洗流水线,高效解决日常办公中90%的脏数据问题,从而将时间留给更有价值的分析工作。

weixin_29215391的博客 582

Go语言如何判断一个chan被关闭

当一个chanel被关闭后,再取出不会阻塞,而是返回零值 package main import "fmt" func main() { c := make(chan int, 5) c <- 123 close(c) fmt.Println(<-c) fmt.Println(<-c) } ...

weixin_30802171的博客 540

大厂硬件机试选择题与判断题解析-卷1

本文精选30道硬件工程师机试题目,涵盖模拟电路、数字电路、PCB设计三大方向。模拟电路部分重点考察运算放大器、滤波器、整流电路等核心知识;数字电路部分聚焦计数器、电平转换等关键技术;PCB设计部分强调高速信号处理、阻抗控制等实践要点。题目均来自华为、小米等大厂真题,剔除基础题,每道题附详细解析,包括正确答案推导过程及相关公式说明。特别针对易错概念(如负反馈类型判断、Q值与带宽关系等)进行重点解析,帮助考生系统掌握硬件设计的核心考点和解题思路。

启芯硬件的博客 677

Go -- 判断chan channel是否关闭的方法

如果不判断chan是否关闭 Notice: 以下代码会产生死循环 代码如下: package main import ( "fmt" ) func main() { c := make(chan int, 10) c &lt;- 1 c &lt;- 2 c &lt;- 3 close(c) for { ...

weixin_33691817的博客 2453

利用ADS建立MIPI D-PHY链路仿真流程

由于MIPI D-PHY的速率并不算高,因此,PCB设计难度通常不大,主要做好差分线的等长、阻抗的连续性、端口处的阻抗优化以及控制好走线的长度,拿到满意的结果还是较为轻松的,最后,建立流程化的仿真工程文件,可以保存为模板,方便日后的设计复用,非常方便。

一只豌豆象的博客 3571

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

关于GOLANG的chan

GOLANG CHANchan是golang中非常重要的一个东西,用来做goroutine的通信,因为golang程序必然会有多个goroutine,如何同步这些goroutine就很重要了。使用chan时有几个心得: 首先,永远是符号<-进行读取或者写入,譬如v,ok := <-c是读取,而c <- v是写入。 其次,读取时,如果没有ok,也是可以读取的。不过如果closed也是能读的,没有赋值而

OSSRS 6874

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【Go - 每日一小问: 对已经关闭的的 chan 进行读写,会怎么样?为什么?】

对已关闭的chan进行读取操作会返回零值并且不会阻塞,可以通过第二个返回值判断chan是否已关闭。对已关闭的chan进行写入操作会导致运行时(panic这种设计确保了数据的一致性和程序的健壮性。

qq_38428433的博客 493

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

golang chan

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34148508的博客 84

go语言学习-- chan与goroutine

chan在go语言中相当于一个文件操作符,使用完成之后需要使用Close()函数关闭。 下面这段代码有两个chan,ch1是一个chan int类型,ch2是一个chan bool类型,ch1被write()函数写入10个数,被read()函数读取,ch2其实是为了防止main所在的goroutine提前退出用的。 func consumer(data chan int,done chan bool){ for{ fmt.Println("receive :",<-data) } d

qq_41514054的博客 506

c++函数为什么带imp_golang 为什么没有判断 close 的接口?

golang 为什么没有判断 close 的接口?关闭 channel 究竟做了什么?`closechan`一个判断 chan 是否 close 的函数思考方法一:通过“写”chan 实现思考方法二:通过“读”chan 实现chan close 原则其实并不需要 `isChanClose` 函数 !!!怎么优雅关闭 chan ?方法一:panic-recover方法二:sync.Once方法三:事...

weixin_29706351的博客 102

go中如何判断一个channel是否关闭

这是一个很简单的方法,但是我在此之前竟然忘记了,但是也确实是在我的项目经历中关于这个chan我从来也没有关闭过,我的经历是只要程序在运行,我的chan就在一直运行,没有关闭过,也就没有了解过这个小方法。我也知道,如果一个chan关闭了,直接去读取数据如果有数据就是数据没有数据就是默认值,但是不能写,写入就是panic;如果有一个有缓冲的chan在写入数据之后,关闭了,再去读取数据是可以读取出来的。一个没有缓冲的chan写入等待数据,关闭,然后也是可以读出这个代写入的数据的,

shunuanwei的博客 995

Golang_13: Go语言 并发编程:协程(goroutine)、通道(chan)、同步锁(Mutex)、WaitGroup、上下文(context)

Go 语言的并发编程使用 协程(goroutine)实现。Go 语言的每一个并发执行的任务称为 goroutine,也包括执行 main() 函数的任务。Go 启动一个 goroutine 非常简单,在任何函数或方法调用前面加上 go 关键字,该函数或方法的调用即异步执行。

谢TS的博客 1693

Golang怎么安全关闭channel_Golang channel关闭教程【通俗】

接收方永远别碰 close(),否则编译失败或运行时 panic。这意味着:如果你函数参数是 ch ,<code>close(ch) 直接报错:invalid operation: close(ch) (cannot close receive-only channel)真正能关 channel 的,是那个创建它、还握着双向或只写类型变量的 goroutine常见错误:把 channel 封装进结构体后暴露 Close() 方法,却没检查内部是否已是只读类型为什么重复 close() 会 panic?

2401_83595681的博客 225

go源码分析-> channel

针对go语言中chan的源码分析channel的机制 1:发送者流程 1:常规检查(发送一个已经关闭的chan会直接触发panic) 2:查看接受则阻塞队列中是否有sudog(对应的一个goroutine,注意是dequeue操作),如果有则直接发送消息到阻塞的goroutine(gp.param = unsafe.Pointer(sg),直接进行指针赋值,具体见chan.go/s...

jacksoom的博客 516

Go Channel 使用的注意事项

重复关闭 Channel 会引发 panic,而向已关闭的 Channel 发送数据同样会导致 panic。接收方可通过 `val, ok := <-ch` 判断 Channel 是否关闭(`ok` 为 `false` 时表示关闭)。Go Channel 是 Go 语言中用于协程间通信的核心机制,其简洁的设计和高效的并发模型使其成为开发者处理并发任务的利器。解决方案包括:使用带缓冲的 Channel、通过 `select` 设置超时,或启动独立的收发协程。**避免未初始化的 Channel**

pojnje_386的博客 39
上一篇: golang解决循环引用的方法
下一篇: grpc结合protobuf生成pb.go文件demo
github_zwl
博客等级 码龄11年 300粉丝 171原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值