好看的皮囊千篇一律,有趣的灵魂万里挑一。
2020-3-1
今天研究了一下channel的源码,对channel的安全退出有了一些小见解。在此结合实际应用,对select 于channel结合对情况下,安全退出channel做一下记录。package main import ( "fmt" "sync" "time" ) var ( wg sync.WaitGroup channel = make(chan int, 10) ) func main() { //先写满一个channel for i := 0; i < 10; i++ { channel <- i } wg.Add(1) go func() { defer wg.Done() for { select { case num := <-channel: fmt.Println("======", num) //每次从channel取值后sleep 1秒,方便我们分析 time.Sleep(time.Duration(num) * time.Second) } } }() wg.Wait() }
package main import ( "fmt" "log" "os" "os/signal" "sync" "syscall" "time" ) var ( wg sync.WaitGroup channel = make(chan int, 10000) ) func main() { //先写满一个channel for i := 0; i < 10; i++ { channel <- i } wg.Add(1) go HandleSignals() wg.Add(1) go func() { defer wg.Done() for { select { case num, ok := <-channel: if !ok { return } fmt.Println("======", num) //每次从channel取值后sleep 1秒,方便我们分析 time.Sleep(time.Duration(num) * time.Second) } } }() wg.Wait() } func HandleSignals() { defer wg.Done() ch := make(chan os.Signal, 10) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR2) for { sig := <-ch switch sig { case syscall.SIGINT, syscall.SIGTERM: close(channel) log.Println("Exiting, please wait...") return } } }
func closechan(c *hchan) { ... lock(&c.lock) if c.closed != 0 { unlock(&c.lock) panic(plainError("close of closed channel")) } ... c.closed = 1 var glist gList // release all readers for { sg := c.recvq.dequeue() if sg == nil { break } if sg.elem != nil { typedmemclr(c.elemtype, sg.elem) sg.elem = nil } if sg.releasetime != 0 { sg.releasetime = cputicks() } gp := sg.g gp.param = nil if raceenabled { raceacquireg(gp, c.raceaddr()) } glist.push(gp) } ... }