在平时开发中,有时会遇到多个线程控制同一个数据的过程,这时候就会遇到锁。我这里写了一个使用匿名方法的例子,用来记录我所遇到的坑(其实以前有写过,不过找不到了,其实也是协程的相关和栈的关系)。
1.先看第一个错误的例子
func load() {
var wg sync.WaitGroup
cm := common{Name: "aa", lk: new(sync.RWMutex)}
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
log.Println(cm.Name, "==i:", i)
defer func() { cm.lk.Unlock(); wg.Done() }()
cm.lk.Lock()
cm.Name = strconv.Itoa(i)
log.Println(cm.Name)
}()
}
wg.Wait()
}
image.png
这里输出都是同一个信息,因为for执行速率较快,go关键字后面还没有执行,for已经完事了,所以可能只有最后一个值。参数还没有来得及将过程中的内容传入,就已经略过了(被重新赋值)
以下是第二种方法,通过参数将i传入。看起来好像严谨,但是还是存在类似的问题,他的根源是因为for在执行的时候,并不用等待内部语句执行完毕,直接赋值,所以这种方式进行传值是不可取的。
func load2() {
var wg sync.WaitGroup
cm := common{Name: "aa", lk: new(sync.RWMutex)}
for i := 0; i < 3; i++ {
wg.Add(1)
go func(i int) {
defer func() { cm.lk.Unlock(); wg.Done() }()
cm.lk.Lock()
log.Println(cm.Name, "==i:", i)
cm.Name = strconv.Itoa(i)
log.Println(cm.Name)
}(i)
}
wg.Wait()
}
正确的方法:
1.使用chan变量进行协程之间的通讯
2.使用锁的方式,比如机构体中,加入锁属性,操作时进行锁定
网友评论