golang select channel 如何保证安全退出,不丢失数据?

栏目: IT技术 · 发布时间: 5年前

内容简介:今天研究了一下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)
    }
    ...
}

原文地址: https://www.yuanshuli.com/post-68.html


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网站项目管理

网站项目管理

[美] 阿什利·弗里德莱因 / 李保庆、杨磊、王增东 / 电子工业出版社 / 2002-11 / 32.00元

这本书全方位地介绍了如何建立和最终交付一个具有很高商业价值的成功网站,讲解从项目管理的角度入手,撇开烦琐的技术细节,更加关注Web项目实施中诸如成本、进度、工作范围等问题,涉及了一个商业网站在实施过程中可能遇到的所有管理细节。书内附国际一流网站开发专家的深邃见解;涵盖了网络项目管理的关键原则及案例研究;通过友情链接,还为读者提供了模板、论坛、术语表、相关链接以及有关因特网知识的测验题。一起来看看 《网站项目管理》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具