面试题答案
一键面试可能出现的问题
- 数据竞争:多个协程同时读写共享数据结构,会导致数据竞争。Go语言中,未正确同步的并发读写同一变量会引发未定义行为,结果可能是随机的,且难以调试。
- 空指针异常:当空接口中包含nil值时,如果未进行适当检查就对其进行解引用操作,会导致空指针异常。例如,将空接口类型断言为具体类型后直接调用方法,如果空接口实际值为nil,就会触发空指针异常。
同步机制设计
- 互斥锁(
sync.Mutex
):- 在读写共享数据结构前,使用互斥锁进行加锁操作,完成读写后解锁。这样可以保证同一时间只有一个协程能够访问共享数据,避免数据竞争。
- 示例代码:
package main
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
data []interface{}
)
func write(value interface{}) {
mu.Lock()
data = append(data, value)
mu.Unlock()
}
func read() []interface{} {
mu.Lock()
defer mu.Unlock()
return data
}
- 读写锁(
sync.RWMutex
):- 如果读操作远远多于写操作,可以使用读写锁。读操作时可以多个协程同时进行(只要没有写操作),写操作时则独占锁,防止其他读写操作。
- 示例代码:
package main
import (
"fmt"
"sync"
)
var (
rwmu sync.RWMutex
data []interface{}
)
func write(value interface{}) {
rwmu.Lock()
data = append(data, value)
rwmu.Unlock()
}
func read() []interface{} {
rwmu.RLock()
defer rwmu.RUnlock()
return data
}
nil值处理逻辑
- 类型断言前检查:在对空接口进行类型断言前,先检查其是否为nil。
- 示例代码:
var i interface{}
// 假设i可能为nil
if i != nil {
if str, ok := i.(string); ok {
fmt.Println(str)
}
}
- 初始化数据结构:在使用共享数据结构前,确保其已正确初始化,避免在nil的切片、map等上进行操作。
- 例如,对于切片:
var data []interface{}
data = make([]interface{}, 0)
- 返回明确的错误:如果在处理空接口值时出现问题,返回明确的错误信息,而不是让程序崩溃。
- 示例代码:
func process(i interface{}) error {
if i == nil {
return fmt.Errorf("received nil value")
}
// 其他处理逻辑
return nil
}
通过合理设计同步机制和妥善处理nil值,可以确保并发Go程序的正确性和稳定性。