内容简介:今天研究了一下channel的源码,对channel的安全退出有了一些小见解。在此结合实际应用,对select 于channel结合对情况下,安全退出channel做一下记录。场景1:直接退出(会丢失数据)因为退出时,直接程序就中断了,channel里存对数据直接丢失。
今天研究了一下channel的源码,对channel的安全退出有了一些小见解。在此结合实际应用,对select 于channel结合对情况下,安全退出channel做一下记录。
场景1:直接退出(会丢失数据)
因为退出时,直接程序就中断了,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()
}
场景2:捕捉程序退出信号,然后关闭channel (不丢失数据)
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
}
}
}
以上实现是在捕捉到系统退出信号时 执行了 close(channel) 。 从而实现,完全退出前,仍将缓存在channel中到数据,读出并执行。
那是怎么实现的呢? 通过阅读源码 go/src/runtime/chan.go: closechan
看到以下实现,可以看到,在close channel时,仍会将channel中的数据读出来。 因此,我们要使用此特性时,就需要根据系统退出信号,关闭channel。然后判断channel是否关闭,若关闭,再退出for循环。 否则,直接退出的程序,就会直接将channel中的数据抛弃。
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)
}
...
}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- JVM安全退出
- SpringBoot优雅退出
- 一次 JVM 进程退出分析
- iOS 登录、退出流程整理
- C# 获取进程退出代码
- 使用xposed更改掘金的侧滑退出的触发范围(左撇子,掘金的这个侧滑退出的体验一言难尽)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
别怕,Excel VBA其实很简单(第2版)
Excel Home / 北京大学出版社 / 2016-7 / 59.00元
对于大部分没有编程基础的职场人士来说,在学习VBA时往往会有很大的畏难情绪。本书正是针对这样的人群,用浅显易懂的语言和生动形象的比喻,并配合大量插画,对Excel中看似复杂的概念和代码,从简单的宏录制、VBA编程环境和基础语法的介绍,到常用对象的操作与控制、执行程序的自动开关—对象的事件、设计自定义的操作界面、调试与优化编写的代码,都进行了形象的介绍。 本书适合那些希望提高工作效率的职场人士......一起来看看 《别怕,Excel VBA其实很简单(第2版)》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
XML 在线格式化
在线 XML 格式化压缩工具