面试题答案
一键面试可能遇到的边界条件问题
- 数据竞争:多个goroutine同时进行类型断言操作,可能会导致对共享数据的竞争,引发未定义行为。例如,当不同goroutine在同一时间尝试读取或修改类型信息时,可能会出现脏读或数据不一致的情况。
- 误判:在并发环境下,由于类型信息的更新和读取可能交错进行,可能会导致类型断言出现误判,将一个实际上不满足接口的对象误判为满足接口。
避免问题确保并发安全的代码示例
- 使用
sync.Mutex
package main
import (
"fmt"
"sync"
)
// 定义一个实现多个接口的类型
type MyType struct {
value int
}
type Interface1 interface {
Method1()
}
type Interface2 interface {
Method2()
}
func (m *MyType) Method1() {
fmt.Println("Method1 called")
}
func (m *MyType) Method2() {
fmt.Println("Method2 called")
}
func main() {
var mu sync.Mutex
var wg sync.WaitGroup
myObj := &MyType{value: 10}
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
if i1, ok := myObj.(Interface1); ok {
i1.Method1()
}
if i2, ok := myObj.(Interface2); ok {
i2.Method2()
}
}()
}
wg.Wait()
}
在这个示例中,通过sync.Mutex
来保护对myObj
的类型断言操作。每次进行类型断言前,先获取锁,操作完成后释放锁,这样可以避免数据竞争。
- 使用
sync.RWMutex
(适用于读多写少场景)
package main
import (
"fmt"
"sync"
)
// 定义一个实现多个接口的类型
type MyType struct {
value int
}
type Interface1 interface {
Method1()
}
type Interface2 interface {
Method2()
}
func (m *MyType) Method1() {
fmt.Println("Method1 called")
}
func (m *MyType) Method2() {
fmt.Println("Method2 called")
}
func main() {
var rwmu sync.RWMutex
var wg sync.WaitGroup
myObj := &MyType{value: 10}
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rwmu.RLock()
defer rwmu.RUnlock()
if i1, ok := myObj.(Interface1); ok {
i1.Method1()
}
if i2, ok := myObj.(Interface2); ok {
i2.Method2()
}
}()
}
wg.Wait()
}
在这个示例中,使用sync.RWMutex
。如果类型断言操作主要是读取操作(即读多写少场景),使用读锁(RLock
)可以允许多个goroutine同时进行类型断言,提高并发性能,同时保证数据的一致性。如果有涉及到修改类型相关数据的操作,需要使用写锁(Lock
)。