利用golang优雅的实现单实例
平时编写代码过程中,经常会遇到对于全局角度只需运行一次的代码,比如全局初始化操作,设计模式中的单例模式。针对单例模式,java中又出现了饿汉模式、懒汉模式,再配合synchronized同步关键字来实现。其目的无非就是将对象只初始化一次,而且最好保证在用到的时候再进行初始化,以避免初始化太早浪费资源,或者两次初始化破坏单例模式的实例唯一性。
Go语言的sync包中提供了一个Once类型来保证全局的唯一性操作,其通过Do(f func())方法来实现,即使** f** 函数发生变化,其也不会被执行,下面我们来看一个小例子:
package main
import (
"fmt"
"sync"
"time"
)
var once sync.Once
func main() {
//once循环调用firstMethod函数10次,其实只执行一次
for i := 0; i < 10; i++ {
once.Do(firstMethod)
fmt.Println("count:---", i)
}
//起10个协程,虽然用once去调secondMethod函数,但该函数不会被执行
//只打印------i
for i := 0; i < 10; i++ {
go func(i int) {
once.Do(secondMethod)
fmt.Println("-----", i)
}(i)
}
//主协程等1min,等上面的10个协程执行完
time.Sleep(1 * time.Second)
}
func firstMethod() {
fmt.Println("firstMethod")
}
func secondMethod() {
fmt.Println("secondMethod")
}
运行程序输出如下结果:
firstMethod
count:--- 0
count:--- 1
count:--- 2
count:--- 3
count:--- 4
count:--- 5
count:--- 6
count:--- 7
count:--- 8
count:--- 9
----- 0
----- 2
----- 4
----- 5
----- 8
----- 6
----- 9
----- 3
----- 7
----- 1
Process finished with exit code 0
然后我们来分析一下:
程序中首先定义了一个名为once的sync.Once类型,然后main函数中第一个for循环10次,但是由于once.Do(f func)中的f函数全局只执行一次,所以firstMethod()函数只被执行一次;之后进入第二个for循环,这里once.Do(f func)方法的参数变为secondMethod函数。起10个协程去调,但由于once.Do(secondMethod)和once.Do(firstMethod)用的是Once类型的同一个实例,所以secondMethod函数实际上不会被执行。这解释了上面运行结果输出。
查看源代码once.go,里面有这样的解释:
if once.Do(f) is called multiple times, only the first call will invoke f,
even if f has a different value in each invocation. A new instance of
Once is required for each function to execute.
大概意思是:如果once.Do(f)被调用多次,只有第一次调用才会执行f函数,即使f是不同的函数。为了每一个函数都被执行,就需要不同的Once实例。
我们查看Once类型的定义:
type Once struct {
m Mutex
done uint32
}
源码中其实用到了互斥锁m和标志位done。然后再看Do方法的实现:
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
每次调用Do方法之前,用atomic包的LoadUint32函数获取标志位done的值,等于1则说明Do方法已经被调用过,直接return,什么都不做。否则利用互斥锁,保证协程安全的去调用f函数,之后把标志位done置为1。
下面我们看一个例子,来实现单实例:
package main
import (
"fmt"
"sync"
"time"
)
var once sync.Once
var mmp map[int]string
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
once.Do(func (){
mmp = make(map[int]string, 10)
})
fmt.Printf("-----%d------%p\n", i, &mmp)
}(i)
}
//主协程等1min,等上面的10个协程执行完
time.Sleep(1 * time.Second)
}
我们起10个协程去竞争初始化类型为字典类型的mmp,然后打印每次mmp的地址,运行输出如下:
-----1------0x50cca0
-----3------0x50cca0
-----2------0x50cca0
-----4------0x50cca0
-----7------0x50cca0
-----6------0x50cca0
-----8------0x50cca0
-----9------0x50cca0
-----5------0x50cca0
-----0------0x50cca0
Process finished with exit code 0
我们可以看到mmp每次地址都一样。如此就轻松优雅就实现了和java单例模式相似的效果。
推荐文章:
本公众号免费提供csdn下载服务,海量IT学习资源,如果你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时我们组建了一个技术交流群,里面有很多大佬,会不定时分享技术文章,如果你想来一起学习提高,可以公众号后台回复【2】,免费邀请加技术交流群互相学习提高,会不定期分享编程IT相关资源。
扫码关注,精彩内容第一时间推给你

利用golang优雅的实现单实例的更多相关文章
- 深入浅出单实例Singleton设计模式
深入浅出单实例Singleton设计模式 陈皓 单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了.这个设计模式主要目的是想在整个系统 ...
- LB(Load balance)负载均衡集群--{LVS-[NAT+DR]单实例实验+LVS+keeplived实验} 菜鸟入门级
LB(Load balance)负载均衡集群 LVS-[NAT+DR]单实例实验 LVS+keeplived实验 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一 ...
- Spring单实例、多线程安全、事务解析
原文:http://blog.csdn.net/c289054531/article/details/9196053 引言: 在使用Spring时,很多人可能对Spring中为什么DAO和Se ...
- Servlet单实例多线程模式
http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以 ...
- xadmin系列之单实例模式
先看下单实例的定义 python的模块实现单例模式是python语言特有的,python的模块天然就是单例的,因为python有个pyc文件,导入一次后,第二次导入直接从pyc中取数据了 这里我们主要 ...
- c#设计应用程序单实例运行
利用WindowsFormsApplicationBase的IsSingleInstance来控制应用程序只能单实例运行. [DllImport("user32.dll", Ent ...
- Oracle DataBase单实例使用ASM案例(1)--ASM基本概念
版权声明:本文为博主原创文章,未经博主允许不得转载. Oracle DataBase单实例使用ASM案例(1)--ASM基本概念 系统环境: 操作系统:RH EL5-64 Oracle 软件: Ora ...
- C#实现单实例运行
C#实现单实例运行的方法,也有多种,比如利用 Process 查找进程的方式,利用 API findwindow 查找窗体的方式,还有就是 利用 Mutex 原子操作,上面几种方法中, 综合考虑利用 ...
- 单实例redis分布式锁的简单实现
redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...
随机推荐
- 相同类中方法间调用时日志Aop失效处理
本篇分享的内容是在相同类中方法间调用时Aop失效处理方案,该问题我看有很多文章描述了,不过大多是从事务角度分享的,本篇打算从日志aop方面分享(当然都是aop,失效和处理方案都是一样),以下都是基于s ...
- Elastic Stack 笔记(六)Elasticsearch5.6 搜索详解
博客地址:http://www.moonxy.com 一.前言 Elasticsearch 主要包含索引过程和搜索过程. 索引过程:一条文档被索引到 Elasticsearch 之后,默认情况下 ES ...
- 生成式学习算法(三)之----高斯判别分析模型(Gaussian Discriminant Analysis ,GDA)
高斯判别分析模型(Gaussian Discriminant Analysis ,GDA) 当我们分类问题的输入特征$x $为连续值随机变量时,可以用高斯判别分析模型(Gaussian Discrim ...
- php 上传word文件 Word文件转 PDF
说一下,之前的时候做上传word文档转pdf的项目时候, 通过安装open office 连接服务组件, 遇到种种问题, 例如上传的word文档版本,, word文档中编辑的样式复杂会出现转pdf失败 ...
- 【linux】记录一个yum update和upgrade的区别
yum update 更新软件包和系统软件.系统内核 yum upgrade只更新软件包,不更新系统软件和系统内核 查看版本号 [root@localhost ~]# uname -r 3.10.0- ...
- 微信小程序中scroll-view的几个坑
微信小程序中scroll-view的几个坑 1:设置scroll-x时,却不能横向滚动,因为view是block组件,但是这里用了flex就不能滚动了(想用flex布局,请开启属性enable-fle ...
- 在vscode中配置python环境
1.安装vscode和python3.7(安装路径在:E:\Python\Python37): 2.打开vscode,在左下角点击设置图标选择setting,搜索python path,在该路径下选择 ...
- There is a cycle in the hierarchy解决
前言: 在一次项目中,分页查询公告列表信息后,在遍历查询到的公告列表时出现了死循环“There is a cycle in the hierarchy”错误,分析原因是因为在公告实体类中包含了商铺对象 ...
- SpringBoot 定时任务实现方式
定时任务实现的几种方式: Timer:是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但 ...
- MYSQL-用户密码修改
解决方法如下:1.终端中结束当前正在运行的mysql进程.# sudo /etc/init.d/mysql stop2.用mysql安全模式运行并跳过权限验证.# sudo /usr/bin/mysq ...