Go编程技巧–Goroutine的优雅控制

Goroutine是Go语言最重要的机制,Goroutine将复杂的需要异步的IO调用抽象成同步调用,符合人类正常的顺序思维,极大的简化了IO编程的难度。如同线程一样,对Goroutine既要掌握基本的用法,更要很好的控制Goroutine的退出机制。本文介绍一种Goroutine的退出思路。

通常Goroutine会因为两种情况阻塞:

  1. IO操作,比如对SocketRead
  2. channel操作。对一个chan的读写都有可能阻塞Goroutine

对于情况1,只需要关闭对应的描述符,阻塞的Goroutine自然会被唤醒。

重点讨论情况2。并发编程,Goroutine提供一种channel机制,channel类似管道,写入者向里面写入数据,读取者从中读取数据。如果channel里面没有数据,读取者将阻塞,直到有数据;如果channel里面数据满了,写入者将因为无法继续写入数据而阻塞。

如果在整个应用程序的生命周期里,writer和reader都表现为一个Goroutine,始终都在工作,那么如何在应用程序结束前,通知它们终止呢?在Go中,并不推荐像abort线程那样,强行的终止Goroutine。因此,抽象的说,必然需要保留一个入口,能够跟writer或reader通信,以告知它们终止。

我们先看reader。我们首先可以想到,利用close函数关闭正在读取的channel,从而可以唤醒reader,并退出。但是考虑到close并不能很好的处理writer(因为writer试图写入一个已经close的channel,将引发异常)。因此,我们需要设计一个额外的只读channel用于通知:

routineSignal的实例,应当通过外部生成并传递给reader,例如:

在reader的循环中,就可以这么写:

当需要终止Goroutine的时候只需要关闭这个额外的channel

看起来很完备了,这可以处理大部分的情况了。这样做有个弊端,尽管,我们可以期望close唤醒Goroutine进而退出,但是并不能知道Goroutine什么时候完成退出,因为Goroutine可能在退出前还有一些善后工作,这个时候我们需要sync.WaitGroup。改造一下routineSignal

增加一个sync.WaitGroup的实例,在Goroutine开始工作时,对wg加1,在Goroutine退出前,对wg减1:

外部,只需要等待WaitGroup返回即可:

只要Wait()返回就能断定Goroutine结束了。

推导一下,不难发现,对于writer也可以采用这种方法。于是,总结一下,我们创建了一个叫routineSignal的结构,结构里面包含一个chan用来通知Goroutine结束,包含一个WaitGroup用于Goroutine通知外部完成善后。这样,通过这个结构的实例优雅的终止Goroutine,而且还可以确保Goroutine终止成功。

                                                                      运维自动化开班啦!

理论结合实战,使学员既可掌握快速从零构建一套实用、完整、可扩展的运维自动化平台:

  • 深度结合使用流行的zabbix、Ansible、Git、Docker、Rancher、ELK等开源框架与工具, 以应用最广泛的django框架为基础,构建一站式运维自动化平台
  •  通过深度剖析与二次开发定制,结合REST API、运维流程化、运维可视化、运维平台化 思想来构造企业级的运维自动化解决方案
  • 在老师带领下大战Zabbix、CMDB、集群自动化部署上线、ELK日志大数据分析、Docker 容器管理平台等多个最新实战,天天实战,招招实用

课程时间:5期运维自动化  8月6日开班

上课模式:网络直播班    线下面授班

询QQ(1)979950755    小夏

   QQ(2)279312229    ada

报名咨询电话:010-56061309

课程大纲:http://www.51reboot.com/course/devops/

文章分类 未分类

发表评论

电子邮件地址不会被公开。

在线交流

数百位业内高手和同行在等你交流
Reboot运维开发分享