Go语言是谷歌2009发布的第二款开源编程语言。
Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。
Go语言在设计上对同步(Synchronization,数据同步和线程同步)提供大量的支持,比如 goroutine和channel同步原语,库层面有
注意:当我说“类”时,是指 Go 里的 struct(单身狗要有面向“对象”编程的觉悟)。
Go语言里对同步的支持主要有五类应用场景:
注意:这里当我说”线程”时,了解Go的同学可以自动映射到 “goroutine”(协程)。
关于 1和2,通过官方文档了解其用法和实现。本系列的主角是 sync 下的工工具类,从 sync.Once 开始。内容分两部分:sync.Once 用法和sync.Once 实现。
在多数情况下,sync.Once 被用于控制变量的初始化,这个变量的读写通常遵循单例模式,满足这三个条件:
在 net 库里,系统的网络配置就是存放在一个变量里,代码如下:
package net
var (
// guards init of confVal via initConfVal
confOnce sync.Once
confVal = &conf{goos: runtime.GOOS}
)
// systemConf returns the machine's network configuration.
func systemConf() *conf {
confOnce.Do(initConfVal)
return confVal
}
func initConfVal() {
dnsMode, debugLevel := goDebugNetDNS()
confVal.dnsDebugLevel = debugLevel
// 省略部分代码...
}
上面这段代码里,confVal 存放数据, confOnce 控制读写,两个都是 package-level 单例变量。由于 Go 里变量被初始化为默认值,confOnce 可以被立即使用,我们重点关注confOnce.Do。首先看成员函数 Do 的定义:
func (o *Once) Do(f func())
Do 接收一个函数作为参数,该函数不接受任务参数,不返回任何参数。具体做什么由使用方决定,错误处理也由使用方控制。
once.Sync 可用于任何符合 “exactly once” 语义的场景,比如:
Go语言中,文件被重复关闭会报error,而 channel 被重复关闭报 panic,once.Sync 可以保证这类事情不发生,但是不能保证其他业务层面的错误。下面这个例子给出了一种错误处理的方式,供大家参考:
// source: os/exec/exec.go
package exec
type closeOnce struct {
*os.File
once sync.Once
err error
}
func (c *closeOnce) Close() error {
c.once.Do(c.close)
return c.err
}
func (c *closeOnce) close() {
c.err = c.File.Close()
}
sync.Once 类通过一个锁变量和原子变量保障 exactly once语义,直接撸下源码(为了便于阅读,做了简化处理):
package sync
import "sync/atomic"
type Once struct {
done uint32
m Mutex
}
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 0 {
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
}
这里 done 是一个状态位,用于判断变量是否初始化完成,其有效值是:
而 m Mutex 用于控制临界区的进入,保证同一时间点最多有一个 f在执行。
done 在 m.Lock() 前后的两次校验都是必要的。
在 Scala 里,有一个关键词 lazy,实现了 sync.Once 同样的功能。具体实现上,早期版本使用了 volatile 修饰状态变量 done,使用 synchronized 替代 m Mutex;后来,也改成了基于CAS的方式。
使用体验上,显然 lazy 更香!
Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软件开发的难度令人沮丧。
¥399.00
¥299.00
¥399.00
¥699.00