1、slice和map并发不安全及解决方法
切片并发不安全,解决办法加锁
var s []int
var lock sync.Mutex //互斥锁
func appendValue(i int) {
lock.Lock() //加锁
s = append(s, i)
lock.Unlock() //解锁
}
func main() {
for i := 0; i < 10000; i++ {
go appendValue(i)
}
//sort.Ints(s) //给切片排序,先排完序再打印,和下面一句效果相同
time.Sleep(time.Second) //间隔1s再打印,防止一边插入数据一边打印时数据乱序
for i, v := range s {
fmt.Println(i, ":", v)
}
}
map并发不安全
解决方法:尽量不要做map的并发,如果用并发要加锁,保证map的操作要么读,要么写。
var lock sync.Mutex
func main() {
m:=make(map[int]int)
go func() { //开一个协程写map
for i:=0;i<10000 ;i++ {
lock.Lock() //加锁
m[i]=i
lock.Unlock() //解锁
}
}()
go func() { //开一个协程读map
for i:=0;i<10000 ;i++ {
lock.Lock() //加锁
fmt.Println(m[i])
lock.Unlock() //解锁
}
}()
time.Sleep(time.Second*20)
}
总结:map在并发执行中会直接报错
https://blog.csdn.net/weixin_43851310/article/details/87897247
2、golang在遍历slice中的坑
package main
import "fmt"
func main() {
pase_student()
}
type student struct {
Name string
Age int
}
func pase_student() {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
m[stu.Name] = &stu // 将临时变量stu的地址给map,最后所有的地址都为同样的一个值
}
for k, v := range m {
fmt.Println(k, v)
}
}
结果为:
原因分析为:
(1)其实还是因为for range创建的是每个元素的拷贝,而不是直接返回每个元素的引用,并且range指向的都是同一个指针(同一个地址)。
(2)将引用传给map,只会获取最后一次拷贝的值。
代码改为:
package main
import "fmt"
func main() {
pase_student()
}
type student struct {
Name string
Age int
}
func pase_student() {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for i, v := range stus {
m[v.Name] = &stus[i]
}
for k, v := range m {
fmt.Println(k, v)
}
}
方法二:
package main
import (
"fmt"
)
func main() {
s :=[]int{1,2,3,4}
m :=make(map[int]*int)
for k,v:=range s{
n:=v
m[k]= &n
}
for key, value := range m {
fmt.Printf("map[%v]=%v\n", key, *value)
}
fmt.Println(m)
}