写点什么

Golang 之不可重入函数实现

  • 2019-11-20
  • 本文字数:1586 字

    阅读完需:约 5 分钟

Golang之不可重入函数实现

一个不可重入的函数就是一个在任何时间点只能执行一次的函数,不管它被调用了多少次,以及有多少 goroutines。


本篇文章说明了阻塞不可重入函数,并在 golang 中产生不可重入的函数实现。

场景用例

某个服务是对某些条件进行轮询,每秒监视一些状态。我们希望每个状态都可以独立地检查,而不需要阻塞。实现可能是这样的:


func main() {    tick := time.Tick(time.Second)    go func() {        for range tick {            go CheckSomeStatus()            go CheckAnotherStatus()        }    }()}
复制代码


我们选择在自己的 goroutine 中运行每个状态检查,以便 CheckAnotherStatus() 不会等待 CheckSomeStatus() 完成。


每一项检查通常都要花费很短的时间,而且比一秒要少得多。但是,如果 CheckAnotherStatus() 本身需要超过一秒的时间运行,会发生什么呢?可能会有一个意外的网络或磁盘延迟影响检查的执行时间。


在同一时间执行两次的函数是否有意义?如果没有,我们希望它是不可重入的。

阻塞,不可重入函数

防止函数多次运行的简单方法是使用 sync.Mutex。


假设我们只关心从上面的循环调用这个函数,我们可以从函数外面实现锁:


import (    "sync"    "time")
func main() { tick := time.Tick(time.Second) var mu sync.Mutex go func() { for range tick { go CheckSomeStatus() go func() { mu.Lock() defer mu.Unlock() CheckAnotherStatus() }() } }()}
复制代码


上面的代码保证了 CheckAnotherStatus() 不是由循环的多次迭代执行的。在以前执行 CheckAnotherStatus() 的时候,循环的任何后续迭代都会被互斥锁阻塞。


阻塞解决方案具有以下属性:


  • 它确保了许多“CheckAnotherStatus()”的调用作为循环迭代的次数。

  • 假设一个执行“CheckAnotherStatus()”的停顿,随后的迭代会导致请求调用相同函数的请求。

屈服,不可重入函数

在我们的状态检查故事中,对随后的 10 个电话堆积起来可能没有意义。一个停滞不前的 CheckAnotherStatus() 执行完成了,所有 10 个调用突然执行,顺序,并且可能在接下来的一秒内完成,在同一秒内完成 10 个相同的检查。


另一个解决办法是屈服。一个有收益的解决方案是:


  • 如果已经执行了“CheckAnotherStatus()”的中止执行。

  • 将最多运行一次“CheckAnotherStatus()”的执行。

  • 与循环迭代的次数相比,实际上可能运行的“CheckAnotherStatus()”的调用更少。


解决方案是通过以下方式实现的:


import (    "sync/atomic"    "time")
func main() { tick := time.Tick(time.Second) var reentranceFlag int64 go func() { for range tick { go CheckSomeStatus() go func() { if atomic.CompareAndSwapInt64(&reentranceFlag, 0, 1) { defer atomic.StoreInt64(&reentranceFlag, 0) } else { return } CheckAnotherStatus() }() } }()}
复制代码


atomic.compareandswapint64(&reentranceFlag, 0, 1) 只有在 reentranceFlag==0 时才会返回 true,并将原子性地设置为 1。在这种情况下,允许进入,并且可以执行该函数。reentranceFlag 保持在 1,直到 CheckAnotherStatus() 完成,此时它被重置。当 CompareAndSwapInt64(…) 返回 false 时,这意味着 reentranceFlag!=0,这意味着该函数已经由另一个 goroutine 执行。代码产生并静默地退出函数。

总结

我们选择在问题的函数之外实现不可重入的代码;我们可以在函数本身中实现它。另外,对于 int64 而言,int32 当然也足够用。以上就是本篇的内容,大家有什么疑问可以在文章下面留言沟通。


本文转载自公众号 360 云计算(ID:hulktalk)。


原文链接:


https://mp.weixin.qq.com/s/6E-tBXc4Sozjr2BkI_0GVA


2019-11-20 16:231157

评论

发布
暂无评论
发现更多内容

简化测试流程,提供卓越服务:TestComplete+Salesforce满足不断发展的企业的需求

龙智—DevSecOps解决方案

2023 腾讯全球数字生态大会,腾讯云研发效能创新与实践专场来啦!

CODING DevOps

Semi D2C 设计稿转代码的演进之路

SemiDesign

figma Semi Design D2C Design to Code

元载万物·智启新界,2023创业邦AIGC技术应用大会在深圳举行

创业邦

不就是接根网线的事么?

小齐写代码

网络技术

自动驾驶点云标注:挑战与解决方案

数据堂

从《孤注一掷》出发,聊聊 SSL 证书的重要性

火山引擎边缘云

https HTTP SSL证书 HTTPS协议

ARTS-WEEK3-23.8.28~23.9.2

Echo!!!

Python 案例实训教学,支持“教师-学生”双视角切换|ModelWhale 版本更新

ModelWhale

Python 人工智能 数据分析 超算 云课堂

从降本增效到价值创造,大模型如何重塑智能语音产品

中关村科金

大模型 智能语音

重磅!腾讯云 CODING 入选软件供应链产品名录

CODING DevOps

国内首个政务领域 Web 引擎 SIG 成立!龙蜥联合儒特科技打造全新一代 Web 架构

OpenAnolis小助手

开源 Web 操作系统 龙蜥社区 龙蜥sig

云原生架构:在云环境中构建弹性应用

树上有只程序猿

微服务 云原生 容器化

重新定义生产力与创造力的新力量

百度开发者中心

人工智能 ChatGPT 生成式AI 文心一言

2023值得关注的125家AIGC企业闪亮发布!

创业邦

今年有什么新内容?《解开网络密钥 - 互联网研究指南》

小猪佩奇身上纹

大模型知识助手,成功切入万亿级企业服务赛道

中关村科金

大模型 知识库

搜索引擎基础《解开网络密钥 - 互联网研究指南》

小猪佩奇身上纹

了解搜索引擎《解开网络密钥 - 互联网研究指南》

小猪佩奇身上纹

软件开发常说的CI/CD是什么

越长大越悲伤

CI/CD

Go 切片

小万哥

Go 程序员 后端 开发 Google

搜索引擎基础《解开网络密钥 - 互联网研究指南》

小猪佩奇身上纹

连接未来,驱动创新|腾讯云 CODING DevOps 主题沙龙完美收官

CODING DevOps

Golang之不可重入函数实现_文化 & 方法_360云计算_InfoQ精选文章