面试题答案
一键面试闭包在Go并发编程中可能出现的问题
- 资源竞争问题:当多个协程同时访问和修改闭包中引用的共享变量时,会出现资源竞争。例如:
package main
import (
"fmt"
)
func main() {
num := 0
var funcs []func()
for i := 0; i < 10; i++ {
funcs = append(funcs, func() {
num = num + 1
fmt.Println(num)
})
}
for _, f := range funcs {
go f()
}
select {}
}
在上述代码中,多个协程同时修改num
变量,由于没有同步机制,最终打印的结果是不确定的,这就是资源竞争。
- 数据一致性问题:同样由于多个协程对共享变量的并发访问,可能导致数据不一致。比如某个协程读取到的数据是部分修改后的状态,而不是完整修改后的数据。
使用同步机制解决问题
- 使用互斥锁(
sync.Mutex
):
package main
import (
"fmt"
"sync"
)
func main() {
num := 0
var mu sync.Mutex
var funcs []func()
for i := 0; i < 10; i++ {
funcs = append(funcs, func() {
mu.Lock()
num = num + 1
fmt.Println(num)
mu.Unlock()
})
}
for _, f := range funcs {
go f()
}
select {}
}
通过mu.Lock()
和mu.Unlock()
,确保在同一时间只有一个协程能够访问和修改num
变量,解决了资源竞争和数据一致性问题。
- 使用通道(
chan
):
package main
import (
"fmt"
)
func main() {
num := 0
ch := make(chan int)
var funcs []func()
for i := 0; i < 10; i++ {
funcs = append(funcs, func() {
ch <- 1
num = num + 1
fmt.Println(num)
<-ch
})
}
for _, f := range funcs {
go f()
}
select {}
}
这里通过通道ch
来控制协程对num
变量的访问,每次只有一个协程能够进入修改num
的代码块,从而解决资源竞争和数据一致性问题。