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), "\n")

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM