面试题答案
一键面试- 初始化全局变量
在Go语言中,有些全局变量的初始化操作开销较大,例如数据库连接池、配置文件加载等。使用
sync.Once
可以确保这些初始化操作只执行一次。
package main
import (
"fmt"
"sync"
)
var (
once sync.Once
config string
)
func loadConfig() {
config = "loaded config"
fmt.Println("Config loaded")
}
func getConfig() string {
once.Do(loadConfig)
return config
}
原因:在并发环境下,如果不使用 sync.Once
,多个协程可能会同时尝试初始化全局变量,导致重复初始化,造成资源浪费或数据不一致。sync.Once
内部通过原子操作和互斥锁保证 loadConfig
函数只被执行一次。
- 单例模式实现
在Go语言中实现单例模式时,
sync.Once
是一种常用的方式。
package main
import (
"fmt"
"sync"
)
type Singleton struct {
data string
}
var (
once sync.Once
instance *Singleton
)
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{
data: "Singleton data",
}
})
return instance
}
原因:在并发环境下,常规的单例实现如果不使用 sync.Once
等机制来同步,可能会创建多个实例。sync.Once
确保了无论有多少个协程同时调用 GetInstance
方法,只会创建一个实例。
- 延迟初始化资源
对于一些可能在程序运行过程中才需要初始化的资源,并且初始化开销较大,使用
sync.Once
可以在需要时进行初始化,并且保证只初始化一次。
package main
import (
"fmt"
"sync"
)
type Resource struct {
value int
}
var (
once sync.Once
resource *Resource
)
func initializeResource() {
resource = &Resource{
value: 42,
}
fmt.Println("Resource initialized")
}
func useResource() {
once.Do(initializeResource)
fmt.Println("Using resource:", resource.value)
}
原因:在程序启动时就初始化所有资源可能会导致启动时间过长,并且有些资源可能在整个程序运行过程中都不会被使用。使用 sync.Once
可以在真正需要使用资源时才进行初始化,同时保证在并发环境下初始化操作的唯一性。