面试题答案
一键面试- 使用
sync.Once
:sync.Once
类型提供了一种简单的机制来确保函数只执行一次,非常适合接口初始化这种场景。- 示例代码如下:
package main
import (
"fmt"
"sync"
)
// 定义一个接口
type MyInterface interface {
DoSomething() string
}
// 接口的实现结构体
type MyStruct struct {
data string
}
func (m *MyStruct) DoSomething() string {
return m.data
}
var myInstance MyInterface
var once sync.Once
func GetInstance() MyInterface {
once.Do(func() {
myInstance = &MyStruct{data: "初始化的数据"}
})
return myInstance
}
func main() {
var wg sync.WaitGroup
numGoroutines := 10
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
instance := GetInstance()
fmt.Println(instance.DoSomething())
}()
}
wg.Wait()
}
- 使用互斥锁
mutex
:- 通过互斥锁可以保证同一时间只有一个goroutine能够初始化接口实例。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
// 定义一个接口
type MyInterface interface {
DoSomething() string
}
// 接口的实现结构体
type MyStruct struct {
data string
}
func (m *MyStruct) DoSomething() string {
return m.data
}
var myInstance MyInterface
var mu sync.Mutex
func GetInstance() MyInterface {
mu.Lock()
defer mu.Unlock()
if myInstance == nil {
myInstance = &MyStruct{data: "初始化的数据"}
}
return myInstance
}
func main() {
var wg sync.WaitGroup
numGoroutines := 10
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
instance := GetInstance()
fmt.Println(instance.DoSomething())
}()
}
wg.Wait()
}
- 使用读写锁
RWMutex
:- 读写锁适用于读多写少的场景,在接口初始化后可能会有较多的读操作。初始化时加写锁,读取时加读锁。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
// 定义一个接口
type MyInterface interface {
DoSomething() string
}
// 接口的实现结构体
type MyStruct struct {
data string
}
func (m *MyStruct) DoSomething() string {
return m.data
}
var myInstance MyInterface
var rwmu sync.RWMutex
func GetInstance() MyInterface {
rwmu.RLock()
if myInstance != nil {
rwmu.RUnlock()
return myInstance
}
rwmu.RUnlock()
rwmu.Lock()
defer rwmu.Unlock()
if myInstance == nil {
myInstance = &MyStruct{data: "初始化的数据"}
}
return myInstance
}
func main() {
var wg sync.WaitGroup
numGoroutines := 10
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
instance := GetInstance()
fmt.Println(instance.DoSomething())
}()
}
wg.Wait()
}
在上述三种方法中,sync.Once
是最简洁且高效的用于确保接口初始化只执行一次的方式。mutex
方式相对简单,但每次获取实例都需要加锁,性能在高并发读场景下不如 RWMutex
和 sync.Once
。RWMutex
适用于读多写少的场景,能在一定程度上提高并发性能。