zoukankan      html  css  js  c++  java
  • go检查channel是否关闭

    golang 中channel 即使已经关闭了, 仍然可以将channel中的数据读出来, 并不会报错。

    一般的写法: data, ok := <- chan,

    只有当channel无数据channel被close了,才会返回ok=false。

    package main
    
    import (
      "context"
      "fmt"
      "reflect"
      "time"
      "unsafe"
    )
    
    func isChanClosed(ch interface{}) bool {
      if reflect.TypeOf(ch).Kind() != reflect.Chan {
        panic("only channels!")
      }
    
      // get interface value pointer, from cgo_export
      // typedef struct { void *t; void *v; } GoInterface;
      // then get channel real pointer
      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
    }
    
    func main() {
      c := make(chan int, 10)
      c <- 1
      c <- 2
      c <- 3
    
      ctx, cancel := context.WithCancel(context.Background())
      close(c)
      cancel()
      fmt.Println("whether channel is closed:", isChanClosed(c), "
    ")
    
    exit:
      for {
        select {
        case i, ok := <-c:
          fmt.Println(ok)
          if !ok {
            fmt.Println("channel closed!")
            break
          }
          fmt.Println(i)
    
        case <-ctx.Done():
          break exit
        }
      }
      fmt.Println("aaaaaaaa")
      time.Sleep(time.Second * 2)
    }
    

      

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

    如果判断golang的channel是否关闭,data, ok := <- chan,当ok不是true的时候,说明是channel关闭了。 那么问题来了,channel关闭了,我们是否可以立马获取到channel被关闭的状态?我想这个问题不少人没有去想吧?为什么有这样的问题?  来自我的一个bug,我期初认为close了一个channel,消费端的goroutine自然是可以拿到channel的关闭状态。然而事实并不是这样的。 只有当channel无数据,且channel被close了,才会返回ok=false。  所以,只要有堆积,就不会返回关闭状态。导致我的服务花时间来消费堆积,才会退出。
    ————————————————
    版权声明:本文为CSDN博主「github_zwl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/github_34457546/article/details/109687879

    参考: https://blog.csdn.net/github_34457546/article/details/109687879

    https://stackoverflow.com/questions/16105325/how-to-check-a-channel-is-closed-or-not-without-reading-it

    ----------------------------------------------

  • 相关阅读:
    八、Docker+RabbitMQ
    Spring.Net学习笔记一(IOC第一个实例)
    快速搞懂 SQL Server 的锁定和阻塞
    JQuery.Ajax()的data参数类型
    常用开源介绍
    AutoMapper简明教程(学习笔记)
    面向.Net程序员的前端优化
    --数组元素插入有两种方式
    JQuery源码分析-02正则表达式-RegExp-常用正则表达式
    关于ASP.NET MVC的Filter小记
  • 原文地址:https://www.cnblogs.com/oxspirt/p/14758785.html
Copyright © 2011-2022 走看看