go数据竞争与锁

给定一个x值,初始值为0,让其自加1000后,再自减1000,如未加锁,情况如下:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	fmt.Println("数据竞争与锁")
	var x int
	//自增1
	for i:=0;i<=1000;i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			x++
		}()
	}
	//自减1
	for i:=0;i<=1000;i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			x--
		}()
	}
	wg.Wait()
	fmt.Println("计算后x值",x)
}

每次运行得到的结果自然不同:

[Running] go run "e:\vsgo\lock.go"
数据竞争与锁
计算后x值 31

[Done] exited with code=0 in 0.964 seconds

[Running] go run "e:\vsgo\lock.go"
数据竞争与锁
计算后x值 10

也就是说,产生了数据竞争,自增和自减函数均对x其进行了无序的操作,得不到想要值0,改进如下:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup
var lock sync.Mutex			//互斥锁
func main() {
	fmt.Println("数据竞争与锁")
	var x int
	//自增1
	for i:=0;i<=1000;i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			lock.Lock()		//加锁
			x++
			lock.Unlock()	//解锁
		}()
	}
	//自减1
	for i:=0;i<=1000;i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			lock.Lock()		//加锁
			x--
			lock.Unlock()	//解锁
		}()
	}
	wg.Wait()
	fmt.Println("计算后x值",x)
}

得到理想值:

[Running] go run "e:\vsgo\lock.go"
数据竞争与锁
计算后x值 0

[Done] exited with code=0 in 1.12 seconds

[Running] go run "e:\vsgo\lock.go"
数据竞争与锁
计算后x值 0

然而实际项目中,互斥锁,锁的开销很大,对性能有影响,代价高。go语言中自带了一个原子性操作函数,atomic进行自增。

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

var wg sync.WaitGroup
func main() {
	fmt.Println("数据竞争与锁")
	var x int32
	//自增1
	for i:=0;i<1000;i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			atomic.AddInt32(&x,1)
		}()
	}
	
	wg.Wait()
	fmt.Println("计算后x值",x)
}

自增1结果:

[Done] exited with code=0 in 0.902 seconds

[Running] go run "e:\vsgo\lock.go"
数据竞争与锁
计算后x值 1000
posted @ 2021-11-13 15:58  柠檬橘  阅读(69)  评论(0编辑  收藏  举报