每日新闻

每日新闻

GoCN每日新闻资讯
有问必答

有问必答

Go相关的问题,技术相关的问题
文章分享

文章分享

技术文章分享,让知识传播给更多的人
招聘应聘

招聘应聘

为Gopher服务的招聘应聘平台

关于规范招聘信息发帖说明 置顶

招聘应聘 回复了问题 • 9 人关注 • 4 个回复 • 5383 次浏览 • 2019-10-04 10:59 • 来自相关话题

golang中指针的赋值是原子的吗?map呢?struct呢?

有问必答h12 回复了问题 • 2 人关注 • 1 个回复 • 54 次浏览 • 16 小时前 • 来自相关话题

CORNERSTONE | DevOps平台是如何实现开发效率的双倍提升?

文章分享CORNERSTONE 发表了文章 • 0 个评论 • 49 次浏览 • 16 小时前 • 来自相关话题

随着企业业务对软件系统日益依赖,IT管理与研发模式也随之对“敏捷”模式产生了需求,也就是今天人们时常提起的DevOps。提升效率,是DevOps实践的核心内容之一。就让我们来一起从软件生命周期的业务流与工作流,探讨DevOps实践效率提升的方向与方法吧。 ...查看全部

随着企业业务对软件系统日益依赖,IT管理与研发模式也随之对“敏捷”模式产生了需求,也就是今天人们时常提起的DevOps。提升效率,是DevOps实践的核心内容之一。就让我们来一起从软件生命周期的业务流与工作流,探讨DevOps实践效率提升的方向与方法吧。


一、CORNERSTONE | DevOps之“流”分析

软件工程将软件的生命周期定义为问题定义、需求分析、软件设计、程序编码、软件测试、运行维护等过程,无论是对于传统模式、敏捷模式还是DevOps模式,软件生命周期过程基本一致,如下图所示。
image.png


软件生命周期各个过程也组成了软件工程的“业务流”,而在不同团队采用相应地开发模式中,具体执行的开发及相关的活动,我们则成为工作流”。


CORNERSTONE,DevOps实践中,最主要改进的内容,就是对于这些 “工作流”的活动进行“关停并转”,从而实现整体与局部上对于效率的提升。


这些工作,也就是需要开展的活动,可以分为以下几类:


人与人的互动

这类活动交互的双方均为自然人,如业务需求收集,活动的特点是具备高度的不规则与不规律性。


人与机的互动

这类活动交互的一方为自然人,一方为依托于计算机的程序,如编码活动、人工审核/审批等,活动的特点是人的活动必须依循计算机相关主题的规则,部分活动可以抽取为规范化的过程。


机与机的互动

这类活动的特点是交互的双方都是依托于计算机的程序,如编译构建、自动化测试,活动的过程高度规范化。不同的作业类型,在效率提升的优化中,需要采用的方法各有不同。


二、CORNERSTONE | DevOps效率提升之协作

协作的本质是在不同的主体之间进行快速、有效的信息共享,从而进一步协调各主体进行步调一致、有序的工作执行,实现整体上的一致性与顺畅性,协作是DevOps实践中效率提升的重要方向和内容之一。

DevOps实践中的协作更多需要是从软件生命周期整体系统化考虑与设计,协作设计上面主要包括以下两个方面。

01、信息共享

传统的模式中,相关业务信息仅共享于各阶段内部,而在CORNERSTONE中,则更强调信息的跨阶段共享,面向产品的全生命周期,共享信息包括:

业务类信息
即业务目标、业务背景、业务需求、业务限制等信息。

执行类信息
即软件开发、编译、测试、部署等执行的相关信息,如开始时间、结束时间、执行时长、执行操作记录等。

反馈类信息
即各步骤、阶段执行的信息反馈,如需求拆分反馈、任务执行反馈、代码编译结果、测试结果、发布验证结果等。

CORNERSTONE为以上信息提供统一的信息管理与分析平台。对于代码编写之前的阶段提供如敏捷协同的工作协同管理模块,以记录需求、任务分配、需求完成进展等信息,对于代码编写之后的阶段,则提供相对完整的执行记录信息以及必要的通知信息,以构建及时的反馈。

02、协作调度

协作调度是DevOps协作实践中另外一项关键内容。通过CORNERSTONE平台,可实现对于“机与机的活动”全自动协作调度,对于“人与机的活动”简化协作调度,对于“人与人的活动”事件驱动协作调度,进而实现优化协作调度的效率,提升协作效果。

全自动协作调度
全自动的协作调度主要是通过CORNERSTONE平台的流水线引擎实现,通过流水线编排的实现指定作业流自动执行,执行过程中自动完成不同阶段的信息交互,过程无需人工参与。

简化的协作调度
简化的协作调度也是通过CORNERSTONE平台的流水线引擎实现,在流水线作业流中编排需要人工干预的节点,但仅需要人工给出通过/终止等简单的指令型信息即可。

基于事件的协作调度
基于事件驱动的协作调度,主要是用于“人与人的活动”,也可以用于“人与机的活动”,其通过通知、待办等事件方式,实现精准的信息共享与推送,驱动协作的下游方快速接受和推进事务工作。

CORNERSTONE中的协作调度的效果可以通过研发效能来进行初步的评估与衡量,通过衡量,我们可以较为清晰的获知哪个阶段的协调调度是关键阻碍点或可以进一步优化。

三、CORNERSTONE | DevOps效率提升之自动化

自动化是DevOps的核心理念,也是效率提升的最重要手段。通过CORNERSTONE一站式云端DevOps平台,实现软件过程自动化以及软件过程的支撑工作自动化。

CORNERSTONE | DevOps全流程解决方案

01、软件过程自动化

软件过程自动化是指在软件的开发、测试、部署等过程中,引入自动化的手段,从而实现快速的软件质量检查,以及软件应用发布。


开发过程自动化


CORNERSTONE的代码助手可帮助编程人员以最快的速度完成编程工作,比如当需要对外部的某个窗口进行操作时,CORNERSTONE的代码助手可进行探测,获取相关的窗口信息,再对其它进行操作等。

image.png


测试过程自动化

CORNERSTONE平台覆盖完整的测试流程,可进行测试用例的编写,建立用例库,减少重复性操作,让研发团队的协作更高效,产品交付更快速。常用的两个功能为:


1)测试用例管理


通过编写测试⽤例,制定测试计划并执⾏,测试结果可直接关联到缺陷,方便对问题进行跟踪处理,实现对迭代质量的全程把控。


 Clipboard Image.png


2)缺陷管理


强大的缺陷管理与统计功能,通过分组、解决状态、优先级等列表对缺陷进行全方位记录与跟踪,同时明确缺陷责任人,及时跟进解决缺陷;同时支持导入导出功能,导出时支持任意格式,不受模板限制。


Clipboard Image.png


部署过程自动化


CORNERSTONE支持依赖脚本pipeline实现的DevOps,支持持续集成与自动化部署,可直接在可视化的服务器上进行操作,同时满足多种开发语言,彻底解决敏捷开发在运维层面的瓶颈,方便开发人员对项目开发生命周期进行全盘管理。


Clipboard Image.png


通过流水线引擎,实现以上内容的自由、可视化编排,以及按需执行。


02、过程支撑自动化

软件过程支撑主要是指面向软件工程过程的支撑,实现自动化包括:


编译构建环境自动化

编译构建环境包括基于DevOps平台的自管理编译构建环境,按需生成编译构建环境,编译构建完成后自动销毁,以及特定编译构建环境的快速接入等。


测试环境自动化

测试环境自动化是指自动化测试执行所需的能力环境,如接口/UI测试脚本所需的执行环境,可以根据测试任务的需要,实现测试环境的弹性伸缩自管理。


环境部署自动化

环境部署自动化是指对于开发、测试、生产等所需要的基础环境,可以根据流水线自动完成环境的使用前的生成、使用后的回收等,实现资源即代码,无需人工参与。


CORNERSTONE中,通过大量的过程及支撑自动化,可以极大的减少开发、测试、运维等工作的人工参与时间,降低人工成本,并能实现人工无法完成的工作,例如快速对10000台服务器上的应用进行更新。但前期的建设需要涉及的技术点较多,成本也较为巨大,如何建设落地自动化,除了考虑效率之外,还需着重考虑业务平台的自主可控与可持续发展等方面。


四、CORNERSTONE | DevOps效率提升之持续优化

持续优化,是CORNERSTONE效率提升的第三个主要方面,也是践行DevOps理念的重要实践。持续优化需要解决优化什么、如何优化等问题。这些问题的解决,需要应用DevOps精益分析的理念实践。精益分析,本质就是对数据的统计、分析与挖掘。


01、数据获取

精益分析所涉及的数据应从需求提出到用户访问形成一个端到端闭环。数据的获取需要从业务系统本身以及支撑业务系统的CORNERSTONE平台两个方向获取。早期可以以CORNERSTONE平台相关数据的获取为主要来源,后续可持续集成来自业务系统埋点获取的数据。在整个过程中,需要做到数据的及时性、准确性与完整性。

02、数据分析

数据分析需要有明确的目标和针对性,如针对业务需求提出到上线的平均周期、开发返工趋势等,通过数据分析,可以快速找到当前影响效率的关键点,从而实现针对性的改善。

image.png

03、数据呈现

数据呈现即为数据应用,数据呈现可以采用两种方式进行。

协同管理
将数据获取/分析的结果,在CORNERSTONE的协同管理平台实时的反馈和呈现,从而推动PO/开发团队/干系人等根据反馈信息快速推进效率优化,通过量变引发质变,通过团队内自我优化的方式实现效率的提升。

度量分析
针对于与效率相关的重点指标,通过可视化图表等方式,进行专项的度量分析,并在管理与项目团队共享指标信息以及指标的变化趋势,通过全局监督的方式推进效率的提升。

五、结论

文化上的协同打破了流程与部门的屏障,共享了信息,协作了调度;过程中的自动化消除了重复性的工作,降低人为风险;业务系统与CORNERSTONE平台的数据支持精准提供优化的方向。DevOps之所以能为企业提升效率在于DevOps的实践实现软件生命周期的业务流与作业流的一致与顺畅。

GoCN每日新闻(2019-10-23)

回复

每日新闻moss 发起了问题 • 1 人关注 • 0 个回复 • 1159 次浏览 • 23 小时前 • 来自相关话题

GoCN每日新闻(2019-09-22)

每日新闻hanyajun 回复了问题 • 2 人关注 • 1 个回复 • 1700 次浏览 • 1 天前 • 来自相关话题

写了一个100%Go语言的Web-Term-SSH 堡垒机项目欢迎大家拍砖

回复

文章分享jjjjerk 发起了问题 • 1 人关注 • 0 个回复 • 128 次浏览 • 1 天前 • 来自相关话题

Go语言自定义自己的SSH-Server

文章分享jjjjerk 发表了文章 • 0 个评论 • 145 次浏览 • 1 天前 • 来自相关话题

原文地址  ...查看全部

Golang-Docker ChromeDP浏览器模拟和截图微服务

文章分享jjjjerk 发表了文章 • 0 个评论 • 214 次浏览 • 2 天前 • 来自相关话题

原文地址  ...查看全部

GoCN每日新闻(2019-10-21)

回复

每日新闻smallfish1 发起了问题 • 1 人关注 • 0 个回复 • 2548 次浏览 • 2 天前 • 来自相关话题

GoCN每日新闻(2019-10-20)

回复

每日新闻lwhile 发起了问题 • 1 人关注 • 0 个回复 • 3151 次浏览 • 3 天前 • 来自相关话题

用 Go 語言實作 Job Queue 機制

文章分享appleboy 发表了文章 • 0 个评论 • 281 次浏览 • 4 天前 • 来自相关话题

很高興可以在  ...查看全部

很高興可以在 Mopcon 分享『用 Go 語言實現 Job Queue 機制』,透過簡單的 goroutine  channel 就可以實現簡單 Queue 機制,並且限制同時可以執行多少個 Job,才不會讓系統超載。最後透過編譯放進 Docker 容器內,就可以跑在各種環境上,加速客戶安裝及部署。

議程大綱

本次大致上整理底下幾個重點:

  1. What is the different unbuffered and buffered channel?
  2. How to implement a job queue in golang?
  3. How to stop the worker in a container?
  4. Shutdown with Sigterm Handling.
  5. Canceling Workers without Context.
  6. Graceful shutdown with worker.
  7. How to auto-scaling build agent?
  8. How to cancel the current Job?

由於在投影片內也許寫得不夠詳細,所以我打算錄製一份影片放在 Udemy 教學影片上,如果有興趣可以參考底下影片連結:

之前的教學影片也可以直接參考底下連結:

投影片

https://www.slideshare.net/appleboy/job-queue-in-golang-184064840

袋鼠存储 v1.3 正式支持移动端

文章分享fabsnail 发表了文章 • 0 个评论 • 260 次浏览 • 4 天前 • 来自相关话题

自袋鼠存储(roostore.com)发布以来,感谢各位的认可,下载使用和积极反馈袋鼠存储致力于为用户提供一种新的存储解决方案,使得用户对 ...查看全部

自袋鼠存储(roostore.com)发布以来,感谢各位的认可,下载使用和积极反馈

袋鼠存储致力于为用户提供一种新的存储解决方案,使得用户对服务可控,对数据可控还有对成本可控

现正式推出 v1.3 版本,该版本包含移动端安卓版,更进一步方便用户使用:

kstore

1. 支持嵌入式提供服务,为移动端提供集成使用
2. 支持跨节点在线查看文件,为移动端提供在线查看图片,播放视频等
3. 提供注册登陆口令控制项,确保公网中的私人节点只允许有口令的用户使用
4. 修复浏览文件夹时滚动条可能不显示问题
5. 修复某些浏览器中点击下载文件无响应问题
6. 修复协程上下文资源未及时释放问题
7. 修复自动登陆或浏览文件夹时可能出现的阻塞问题
8. 修复长时间运行过程中周期性查找更多可用连接节点时可能出现的并发崩溃问题


移动端(安卓版首发)
1. 支持在指定的服务器上进行注册,登陆
2. 支持使用集成服务,满足无自部署 kstore 服务时使用
3. 提供断点上传手机中的文件,支持暂停、恢复,取消和清空(已完成)任务
4. 提供断点下载文件到手机,支持暂停,恢复,取消和清空(已完成)任务
5. 提供将下载的文件分享发送给其他应用
6. 提供文件浏览,创建删除文件(夹)
7. 提供文件剪切,复制,粘贴,重命名以及查看文件详细信息等
8. 支持下拉刷新文件列表
9. 支持查看图片(jpg, jpeg, png, gif, svg等格式),包括查看其他 kstore 节点中的图片(不存储文件到本地)
10. 支持播放视频(mp4, mov),包括查看其他 kstore 节点中的视频(不存储文件到本地)
11. 支持 admin 后台管理(目前仅支持网络管理部分)
12. 支持是否显示目录大小选项设置
13. 提供帮助与反馈渠道
14. 提供将 kstore-app 推荐给好友


感兴趣的朋友,欢迎通过官网 roostore.com 下载使用

注:iPhone 版本正在努力攻关一些关键技术问题,相信很快也会与大家见面

GoCN每日新闻(2019-10-19)

回复

每日新闻mahuaibo 发起了问题 • 1 人关注 • 0 个回复 • 3362 次浏览 • 4 天前 • 来自相关话题

求助:有没有热升级/自动化升级的框架

有问必答astaxie 回复了问题 • 2 人关注 • 1 个回复 • 133 次浏览 • 5 天前 • 来自相关话题

go 学习笔记之解读什么是defer延迟函数

文章分享snowdreams1006 发表了文章 • 0 个评论 • 234 次浏览 • 5 天前 • 来自相关话题

Go 语言中有个 defer 关键字,常用于实现延迟函数来保证关键代码的最终执行,常言道: "未雨绸缪方可有备无患".


延迟函数就是这么一种机制,无论程序是正常返回还是异常报错,只要存在延迟函数都能保证这部分关键逻辑最终执行,所以用来做些资源清理等操作再合适不过了.


go-error-about-defer.jpg
go-error-about-defer.jpg

出入成双有始有终


日常开发编程中,有些操作总是成双成对出现的,有开始就有结束,有打开就要关闭,还有一些连续依赖关系等等.


一般来说,我们需要控制结束语句,在合适的位置和时机控制结束语句,手动保证整个程序有始有终,不遗漏清理收尾操作.


最常见的拷贝文件操作大致流程如下:



  1. 打开源文件


srcFile, err := os.Open("fib.txt")
if err != nil {
t.Error(err)
return
}


  1. 创建目标文件


dstFile, err := os.Create("fib.txt.bak")
if err != nil {
t.Error(err)
return
}


  1. 拷贝源文件到目标文件


io.Copy(dstFile, srcFile)


  1. 关闭目标文件


dstFile.Close()
srcFile.Close()


  1. 关闭源文件


srcFile.Close()

值得注意的是: 这种拷贝文件的操作需要特别注意操作顺序而且也不要忘记释放资源,比如先打开再关闭等等!


func TestCopyFileWithoutDefer(t *testing.T) {
srcFile, err := os.Open("fib.txt")
if err != nil {
t.Error(err)
return
}

dstFile, err := os.Create("fib.txt.bak")
if err != nil {
t.Error(err)
return
}

io.Copy(dstFile, srcFile)

dstFile.Close()
srcFile.Close()
}


「雪之梦技术驿站」: 上述代码逻辑还是清晰简单的,可能不会忘记释放资源也能保证操作顺序,但是如果逻辑代码比较复杂的情况,这时候就有一定的实现难度了!



可能是为了简化类似代码的逻辑,Go 语言引入了 defer 关键字,创造了"延迟函数"的概念.



  • defer 的文件拷贝


func TestCopyFileWithoutDefer(t *testing.T) {
if srcFile, err := os.Open("fib.txt"); err != nil {
t.Error(err)
return
} else {
if dstFile,err := os.Create("fib.txt.bak");err != nil{
t.Error(err)
return
}else{
io.Copy(dstFile,srcFile)

dstFile.Close()
srcFile.Close()
}
}
}


  • defer 的文件拷贝


func TestCopyFileWithDefer(t *testing.T) {
if srcFile, err := os.Open("fib.txt"); err != nil {
t.Error(err)
return
} else {
defer srcFile.Close()

if dstFile, err := os.Create("fib.txt.bak"); err != nil {
t.Error(err)
return
} else {
defer dstFile.Close()

io.Copy(dstFile, srcFile)
}
}
}

上述示例代码简单展示了 defer 关键字的基本使用方式,显著的好处在于 Open/Close 是一对操作,不会因为写到最后而忘记 Close 操作,而且连续依赖时也能正常保证延迟时机.


简而言之,如果函数内部存在连续依赖关系,也就是说创建顺序是 A->B->C 而销毁顺序是 C->B->A.这时候使用 defer 关键字最合适不过.


懒人福音延迟函数



官方文档相关表述见 Defer statements[1]



如果没有 defer 延迟函数前,普通函数正常运行:


func TestFuncWithoutDefer(t *testing.T) {
// 「雪之梦技术驿站」: 正常顺序
t.Log("「雪之梦技术驿站」: 正常顺序")

// 1 2
t.Log(1)
t.Log(2)
}

当添加 defer 关键字实现延迟后,原来的 1 被推迟到 2 后面而不是之前的 1 2 顺序.


func TestFuncWithDefer(t *testing.T) {
// 「雪之梦技术驿站」: 正常顺序执行完毕后才执行 defer 代码
t.Log(" 「雪之梦技术驿站」: 正常顺序执行完毕后才执行 defer 代码")

// 2 1
defer t.Log(1)
t.Log(2)
}

如果存在多个 defer 关键字,执行顺序可想而知,越往后的越先执行,这样才能保证按照依赖顺序依次释放资源.


func TestFuncWithMultipleDefer(t *testing.T) {
// 「雪之梦技术驿站」: 猜测 defer 底层实现数据结构可能是栈,先进后出.
t.Log(" 「雪之梦技术驿站」: 猜测 defer 底层实现数据结构可能是栈,先进后出.")

// 3 2 1
defer t.Log(1)
defer t.Log(2)
t.Log(3)
}

相信你已经明白了多个 defer 语句的执行顺序,那就测试一下吧!


func TestFuncWithMultipleDeferOrder(t *testing.T) {
// 「雪之梦技术驿站」: defer 底层实现数据结构类似于栈结构,依次倒叙执行多个 defer 语句
t.Log(" 「雪之梦技术驿站」: defer 底层实现数据结构类似于栈结构,依次倒叙执行多个 defer 语句")

// 2 3 1
defer t.Log(1)
t.Log(2)
defer t.Log(3)
}

初步认识了 defer 延迟函数的使用情况后,我们再结合文档详细解读一下相关定义.



  • 英文原版文档



A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns,either because the surrounding function executed a return statement,reached the end of its function body,or because the corresponding goroutine is panicking.




  • 中文翻译文档



"defer"语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻,这是因为周围函数执行了一个return语句,到达了函数体的末尾,或者是因为相应的协程正在惊慌.



具体来说,延迟函数的执行时机大概分为三种情况:


周围函数执行 return



because the surrounding function executed a return statement



return 后面的 t.Log(4) 语句自然是不会运行的,程序最终输出结果为 3 2 1 说明了 defer 语句会在周围函数执行 return 前依次逆序执行.


func funcWithMultipleDeferAndReturn() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
return
fmt.Println(4)
}

func TestFuncWithMultipleDeferAndReturn(t *testing.T) {
// 「雪之梦技术驿站」: defer 延迟函数会在包围函数正常return之前逆序执行.
t.Log(" 「雪之梦技术驿站」: defer 延迟函数会在包围函数正常return之前逆序执行.")

// 3 2 1
funcWithMultipleDeferAndReturn()
}

周围函数到达函数体



reached the end of its function body



周围函数的函数体运行到结尾前逆序执行多个 defer 语句,即先输出 3 后依次输出 2 1.
最终函数的输出结果是 3 2 1 ,也就说是没有 return 声明也能保证结束前执行完 defer 延迟函数.


func funcWithMultipleDeferAndEnd() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
}

func TestFuncWithMultipleDeferAndEnd(t *testing.T) {
// 「雪之梦技术驿站」: defer 延迟函数会在包围函数到达函数体结尾之前逆序执行.
t.Log(" 「雪之梦技术驿站」: defer 延迟函数会在包围函数到达函数体结尾之前逆序执行.")

// 3 2 1
funcWithMultipleDeferAndEnd()
}

当前协程正惊慌失措



because the corresponding goroutine is panicking



周围函数万一发生 panic 时也会先运行前面已经定义好的 defer 语句,而 panic 后续代码因为没有特殊处理,所以程序崩溃了也就无法运行.


函数的最终输出结果是 3 2 1 panic ,如此看来 defer 延迟函数还是非常尽忠职守的,虽然心里很慌但还是能保证老弱病残先行撤退!


func funcWithMultipleDeferAndPanic() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
panic("panic")
fmt.Println(4)
}

func TestFuncWithMultipleDeferAndPanic(t *testing.T) {
// 「雪之梦技术驿站」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.
t.Log(" 「雪之梦技术驿站」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.")

// 3 2 1
funcWithMultipleDeferAndPanic()
}

通过解读 defer 延迟函数的定义以及相关示例,相信已经讲清楚什么是 defer 延迟函数了吧?


简单地说,延迟函数就是一种未雨绸缪的规划机制,帮助开发者编程程序时及时做好收尾善后工作,提前做好预案以准备随时应对各种情况.



  • 当周围函数正常执行到到达函数体结尾时,如果发现存在延迟函数自然会逆序执行延迟函数.

  • 当周围函数正常执行遇到 return 语句准备返回给调用者时,存在延迟函数时也会执行,同样满足善后清理的需求.

  • 当周围函数异常运行不小心 panic 惊慌失措时,程序存在延迟函数也不会忘记执行,提前做好预案发挥了作用.


所以不论是正常运行还是异常运行,提前做好预案总是没错的,基本上可以保证万无一失,所以不妨考虑考虑 defer 延迟函数?


go-error-about-lovely.png
go-error-about-lovely.png

延迟函数应用场景


基本上成双成对的操作都可以使用延迟函数,尤其是申请的资源前后存在依赖关系时更应该使用 defer 关键字来简化处理逻辑.


下面举两个常见例子来说明延迟函数的应用场景.



  • Open/Close


文件操作一般会涉及到打开和开闭操作,尤其是文件之间拷贝操作更是有着严格的顺序,只需要按照申请资源的顺序紧跟着defer 就可以满足资源释放操作.


func readFileWithDefer(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
return ioutil.ReadAll(f)
}


  • Lock/Unlock


锁的申请和释放是保证同步的一种重要机制,需要申请多个锁资源时可能存在依赖关系,不妨尝试一下延迟函数!


var mu sync.Mutex
var m = make(map[string]int)
func lookupWithDefer(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}

总结以及下节预告


defer 延迟函数是保障关键逻辑正常运行的一种机制,如果存在多个延迟函数的话,一般会按照逆序的顺序运行,类似于栈结构.


延迟函数的运行时机一般有三种情况:



  • 周围函数遇到返回时


func funcWithMultipleDeferAndReturn() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
return
fmt.Println(4)
}


  • 周围函数函数体结尾处


func funcWithMultipleDeferAndEnd() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
}


  • 当前协程惊慌失措中


func funcWithMultipleDeferAndPanic() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
panic("panic")
fmt.Println(4)
}

本文主要介绍了什么是 defer 延迟函数,通过解读官方文档并配套相关代码认识了延迟函数,但是延迟函数中存在一些可能令人比较迷惑的地方.


go-error-about-question.png
go-error-about-question.png

读者不妨看一下下面的代码,将心里的猜想和实际运行结果比较一下,我们下次再接着分享,感谢你的阅读.


func deferFuncWithAnonymousReturnValue() int {
var retVal int
defer func() {
retVal++
}()
return 0
}

func deferFuncWithNamedReturnValue() (retVal int) {
defer func() {
retVal++
}()
return 0
}

延伸阅读参考文档



  • Defer_statements[2]

  • go 语言的 defer 语句[3]

  • Go defer 实现原理剖析[4]

  • go 语言 defer 你不知道的秘密![5]

  • Go 语言中 defer 的一些坑[6]

  • go defer (go 延迟函数)[7]



如果本文对你有所帮助,不用赞赏,点赞鼓励一下就是最大的认可,顺便也可以关注下微信公众号「 雪之梦技术驿站 」哟!



雪之梦技术驿站.png
雪之梦技术驿站.png

参考资料



[1]

Defer statements: https://golang.google.cn/ref/spec#Defer_statements



[2]

Defer_statements: https://golang.google.cn/ref/spec#Defer_statements



[3]

go语言的defer语句: https://www.jianshu.com/p/5b0b36f398a2



[4]

Go defer实现原理剖析: https://studygolang.com/articles/16067



[5]

go语言 defer 你不知道的秘密!: https://www.cnblogs.com/baizx/p/5024547.html



[6]

Go语言中defer的一些坑: https://www.jianshu.com/p/79c029c0bd58



[7]

go defer (go延迟函数): https://www.cnblogs.com/ysherlock/p/8150726.html