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
----------------------------------------------
