当前位置: 首页 > news >正文

北京网站开发不限年龄江西响应式网页建设

北京网站开发不限年龄,江西响应式网页建设,程序员免费自学网站,wordpress主题还原在使用Golang做后端开发的工程中,我们通常需要声明一些一些配置类或服务单例等在业务逻辑层面较为底层的实例。为了节省内存或是冷启动开销,我们通常采用lazy-load懒加载的方式去初始化这些实例。初始化单例这个行为是一个非常经典的并发处理的案例&…

在使用Golang做后端开发的工程中,我们通常需要声明一些一些配置类或服务单例等在业务逻辑层面较为底层的实例。为了节省内存或是冷启动开销,我们通常采用lazy-load懒加载的方式去初始化这些实例。初始化单例这个行为是一个非常经典的并发处理的案例,比如在java当中,我们可能用到建立双重锁+volatile的方式保证初始化逻辑只被访问一次,并且所有线程最终都可以读取到初始化完成的实例产物。这段经典的代码可以按如下的方式编写:

// 参考:https://blog.csdn.net/qq_27489007/article/details/84966680public class Singleton {private volatile static Singleton uniqueSingleton;private Singleton() {}public Singleton getInstance() {if (null == uniqueSingleton) {synchronized (Singleton.class) {if (null == uniqueSingleton) {uniqueSingleton = new Singleton();}}}return uniqueSingleton;}
}

但在Golang里面,实现懒加载的方式可以简单的多,用内置的sync.Once就能满足。假设我们有一个user单例,需要被1000个线程读取并打印,就可以这样子写:

type User struct {Name string `json:"name"`Age  int    `json:"age"`
}var user *User
var userOnce sync.Oncefunc initUser() {user = &User{}cfgStr := `{"name":"foobar","age":18}`if err := json.Unmarshal([]byte(cfgStr), user); err != nil {panic("load user err: " + err.Error())}
}func getUser() *User {userOnce.Do(initUser)return user
}func TestSyncOnce(t *testing.T) {var wg sync.WaitGroupfor i := 1; i < 1000; i++ {wg.Add(1)go func(n int) {defer wg.Done()curUser := getUser()t.Logf("[%d] got user: %+v", n, curUser)}(i)}wg.Wait()
}

这段代码里,首先是通过var userOnce sync.Once声明了一个sync.Once实例,然后在getUser当中,我们声明了userOnce.Do(initUser)这个操作。假设一个goroutine最先到达这个操作,就会上锁并执行initUser,其它goroutine到达之后,得等第一个goroutine执行完initUser之后,才会继续return user。这样,就能一来保证initUser只会执行一次,二来所有goroutine都能够最终读到初始化完成的user单例。

sync.Once的工作机理也很简单,通过一个锁和一个flag就能够实现:

func (o *Once) Do(f func()) {if atomic.LoadUint32(&o.done) == 0 { // 如果是1表示已经完成了,跳过o.doSlow(f)}
}func (o *Once) doSlow(f func()) {o.m.Lock() // 只有1个goroutine能拿到锁,其它的等待defer o.m.Unlock()if o.done == 0 { // 如果还是0表示第一个来的,不是0就表示已经有goroutine做完了defer atomic.StoreUint32(&o.done, 1)f()}
}

最后也需要注意,sync.Once使用上面有一个坑点,不能也不需要像java一样为单例提前做nil判断。比如下面一段代码是有问题的:

func initUser() {user = &User{} // 先给一个zero-value实例cfgStr := `{"name":"foobar","age":18}` // 然后加载json内容,完成初始化if err := json.Unmarshal([]byte(cfgStr), user); err != nil {panic("load user err: " + err.Error())}
}func getUser() *User {if user == nil {userOnce.Do(initUser)}return user
}

由于Golang没有volatile关键字,不能控制单例在内存的可见性,那么多goroutine并发时,就有可能出现这样的执行时序:

  • goroutine-A过了getUseruser == nil判断,进入到了initUser逻辑,走到了cfgStr := XXX一行
  • 此时切换到goroutine-B,因为goroutine-AinitUser已经走过了user = &User{}一行,所以跳过了user == nil判断,直接返回没有完全初始化的user实例,然后一直往下运行,就没切回给goroutine-A

这样的结果,就导致有goroutine拿到未初始化完成的实例往后运行,后面就出问题了。所以实战当中需要留意,用sync.Once时,不能也不需要加这些nil判断,就能满足懒加载单例/配置之类的逻辑。

http://www.yayakq.cn/news/431274/

相关文章:

  • 南京做网站seo的无网站做cpa
  • 2017年网站建设市场分析如何拥有自己的网站
  • 南平购物网站开发设计自己家的电脑宽带50m做网站服务器
  • 企业网站建设论文模板wordpress评论采集发布
  • 如何免费建设公司网站制作精美网站建设口碑好
  • 怎么在南京人社网站做失业登记wordpress怎样创建门户网站
  • 建立企业网站选什么好广州公司注册多少钱
  • 湘潭做网站口碑好磐石网络旅游地网站制作
  • 做钓鱼网站会被抓判刑吗云南楚雄旅游必去的景点
  • 织梦企业网站管理系统黄聪wordpress
  • 设计网站公司力荐亿企邦成都网站建设天府科蓝
  • 营销型企业网站建设的预算跨境电商 网站开发
  • 如何做强一个网站的品牌wordpress 响应 主题
  • 网站域名每年费用中国建筑出国招聘网
  • 好看的美食怎么做视频网站买空间网
  • 网站建设页面大小做物流网站
  • 网站建设 思维导图企业如何数字化转型
  • 南阳市网站建设阿里云域名注册步骤
  • 对做网站有什么建议WordPress会员注册管理
  • 虚拟主机与网站建设网站网络安全怎么做
  • 行业网站排名张家港城市建设规划局网站
  • 网站做平台前端开发工程师需要具备哪些能力
  • 招标网站排名前十名什么是网络营销市场营销学
  • 一个网站建设大概需要多少费用网站建设的职位类别
  • dede网站经常被挂马 怎么办人才网站的会计账如何做
  • 微信小网站制作网站由哪儿三部分组成
  • 做影视网站引流重庆seo教程搜索引擎优化
  • 前台和后台网站开发的区别企业信息服务平台
  • 厦门做企业网站比较好的公司wordpress教程图书
  • 上海市建设工程交易服务中心网站湖北专业网站建设设计