Go 单例模式[个人翻译]
原文地址:http://marcio.io/2015/07/singleton-pattern-in-go/
常识性错误
最近,我在很多Github库里看到这种类型的错误,单例模式的实现没有考虑线程安全,下面是常识性错误的代码
package singleton type singleton struct {
} var instance *singleton func GetInstance() *singleton {
if instance == nil {
instance = &singleton{} // <---非线程安全的
}
return instance
}
激进的锁
我也看到一些使用糟糕的方法来解决线程安全的问题。事实上他解决了多线程的问题,但是创造了其他潜在的更严重的问题,他通过对整个方法执行锁定来引入线程竞争
var mu Sync.Mutex func GetInstance() *singleton {
mu.Lock() // <--- 如果实例已经被创建就没有必要锁写
defer mu.Unlock() if instance == nil {
instance = &singleton{}
}
return instance
}
Check-Lock-Check 模式
在c++和其他语言,用于保证最小锁定并且保证线程安全的最好、最安全的方式是当需要锁定时使用众所周知的Check-Lock-Check模式。下面的伪代码说明了这个模式的大概样子
if check() {
lock() {
if check() {
// perform your lock-safe code here
}
}
}
func GetInstance() *singleton {
if instance == nil { // <-- 不够完善. 他并不是完全的原子性
mu.Lock()
defer mu.Unlock() if instance == nil {
instance = &singleton{}
}
}
return instance
}
import "sync"
import "sync/atomic" var initialized uint32
... func GetInstance() *singleton { if atomic.LoadUInt32(&initialized) == {
return instance
} mu.Lock()
defer mu.Unlock() if initialized == {
instance = &singleton{}
atomic.StoreUint32(&initialized, )
} return instance
}
但是.....我相信我们可以通过查看Go语言和标准库的源码看一下go routines 同步的实现方式来做的更好
Go惯用的单例方法
我们想要使用Go的惯用手法来实现这个单例模式。所以我们需要看一下打包好的sync标准库。我们找到了 Once 类型。这个对象可以精确的只执行一次操作,下面就是Go标准库的代码
// Once is an object that will perform exactly one action.
type Once struct {
m Mutex
done uint32
} // Do calls the function f if and only if Do is being called for the
// first time for this instance of Once. In other words, given
// var once Once
// 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.
//
// Do is intended for initialization that must be run exactly once. Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
// config.once.Do(func() { config.init(filename) })
//
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
// If f panics, Do considers it to have returned; future calls of Do return
// without calling f.
//
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == { // <-- Check
return
}
// Slow-path.
o.m.Lock() // <-- Lock
defer o.m.Unlock()
if o.done == { // <-- Check
defer atomic.StoreUint32(&o.done, )
f()
}
}
这意味着我们可以运用非常棒的 Go sync包来调用一个只执行一次的方法。因此,我们可以向下面这样调用 once.Do() 方法
once.Do(func() {
// 执行安全的初始化操作
})
下面你可以看到使用sync.Once类型实现的单例实现的完整代码,用于同步访问GetInstance() 并保证我们的类型初始化只执行一次。
package singleton import (
"sync"
) type singleton struct {
} var instance *singleton
var once sync.Once func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
总结
Go 单例模式[个人翻译]的更多相关文章
- Go语言中的单例模式(翻译)
在过去的几年中,Go语言的发展是惊人的,并且吸引了很多由其他语言(Python.PHP.Ruby)转向Go语言的跨语言学习者. Go语言太容易实现并发了,以至于它在很多地方被不正确的使用了. Go语言 ...
- Go语言之路—博客目录
Go语言介绍 为什么你应该学习Go语言? 开发环境准备 从零开始搭建Go语言开发环境 VS Code配置Go语言开发环境 Go语言基础 Go语言基础之变量和常量 Go语言基础之基本数据类型 Go语言基 ...
- [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...
- 【白话设计模式四】单例模式(Singleton)
转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...
- Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)
Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...
- 【Java】Java 深入探讨 单例模式的实现
在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在 ...
- 深入Java单例模式【转载】
在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在 ...
- spring aop配置文档部分翻译
欢迎转载交流: http://www.cnblogs.com/shizhongtao/p/3476973.html 下面的文字来自官方文档的翻译,具体事例以后奉上. Advisors "ad ...
- Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)
# 禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译) - 原文 <https://githu ...
随机推荐
- 团队作业八-Beta版本冲刺计划及安排
Beta版本冲刺计划及安排 目录: 1.介绍小组新加入的成员,他担任的角色 2.下一阶段需要改进完善的功能 3.下一阶段新增(或修改)的功能 4.需要改进的团队分工 5.需要改进的工具流程 6.冲刺的 ...
- 201521123067 《Java程序设计》第4周学习总结
201521123067 <Java程序设计>第4周学习总结 1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. ●总结: (1)在 ...
- python学习笔记1.2
在python中%的用处是求余数,而不是除数.
- 201521123036 《Java程序设计》第14周学习总结
本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 书面作业 MySQL数据库基本操作 1.1 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) ...
- Java课设(学生信息管理系统)
1.团队课程设计博客链接 http://www.cnblogs.com/Min21/p/7064093.html 2.个人负责模板或任务说明 设计登陆界面和学生信息界面的设计,学生信息的显示.退出等功 ...
- 201521123048 《java程序设计》 第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1. ...
- JAVA课程设计-----加减法测试博客
1.团队成员介绍(一个人做的) 谢季努:网络1513 201521123079 2.项目git地址 3.项目git提交截图 4.项目运行截图 输入答案后点击确认就会出现本次的得分 如果觉得成绩不理想点 ...
- 201521123079《java程序设计》第9周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...
- Java第十一周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...
- 通过SDK和API获取阿里云RDS的监控数据
阿里云的RDS自带的监控系统获取数据不怎么直观,想要通过API获取数据通过zabbix显示,因为网上资料缺乏和其他一些原因,获取API签名很困难,但使用阿里云的SDK可以完美避开获取签名的步骤. 阿里 ...