golang 开发: WaitGroup Mutex

CSP is the abbreviation of Communicating Sequential Process. Chinese can be called Communication Sequential Process. It is a concurrent programming model. It was originally described in Tony Hoare's 1977 paper and influenced the design of many programming languages.

golang CSP model

The golang language does not fully implement all the theories of the CSP model, but only borrows the two concepts of process and channel. The performance of process in the golang language is goroutine, which is an entity that actually executes concurrently. Each entity communicates through channel to realize data sharing.
The most classic data communication sharing theory

Share memory by communication

Do not communicate by sharing memory; instead, share memory by communicating

Don't communicate by way of shared memory, on the contrary, share memory through communication.
This is the basic communication theory for golang to achieve high concurrency.
In the golang language, data communication between multiple goroutines is achieved through channels.

sync.WaitGroup use

If you need to make multiple goroutines complete, use time.sleep, delay a few seconds to ensure that each goroutine can be executed.

func testPrint(i int) {
	fmt.Println(i)
}
func main() {
	for i:=0;i<5;i++ {
		go testPrint(i)
	}
	time.Sleep(time.Second)
}

However, it is impossible to write this in production projects. A delay of 1S may cause all goroutines to be executed without completion, a delay of 1000S may be executed in 1 millisecond, and other 999S are waiting, which prolongs the execution time of the program.
So there is sync.WaitGroup

func testPrint(wg *sync.WaitGroup, i int) {
	fmt.Println(i)
	wg.Done()
}
func main() {
	var wg = new(sync.WaitGroup)
	for i:=0;i<5;i++ {
		wg.Add(1)
		go testPrint(wg,i)
	}
	wg.Wait()
}

WaitGroup is easier to understand. In fact, it is an internal counter. Before executing the goroutine behavior, execute wg.Add(1) and give the counter +1. After the execution, execute wg.Done(), which means that the execution of the goroutine is completed and the counter is -1. , Wg.Wait() will block the execution of the code, wait for all the goroutines added to the WaitGroup to be executed (the counter is reduced to 0), and then exit the program.
It perfectly solves the need to wait for all goroutines to be executed.

sync.Mutex

sync.Mutex, exclusive lock of mutex.
We need to maintain a variable to ensure that each goroutine can successfully modify it. If there is no mutex, it may be the following code

func testPrint(wg *sync.WaitGroup, i int) {
	count++
	fmt.Println(i)
	wg.Done()
}
var count int
func main() {
	count = 0
	var wg = new(sync.WaitGroup)
	for i:=0;i<500;i++ {
		wg.Add(1)
		go testPrint(wg,i)
	}
	wg.Wait()
	fmt.Printf("count:%d",count)
}

Expected to be a specific value, 500. In fact, it is often not 500. It is because multiple goroutines modify the count value at the same time, and try it with a mutex lock.

func testPrint(wg *sync.WaitGroup, i int) {
	defer func() {
		mu.Unlock()
	}()
	mu.Lock()
	count++
	fmt.Println(i)
	wg.Done()
}
var count int
var mu *sync.Mutex
func main() {
	count = 0
	mu = new(sync.Mutex)
	var wg = new(sync.WaitGroup)
	for i:=0;i<500;i++ {
		wg.Add(1)
		go testPrint(wg,i)
	}
	wg.Wait()
	fmt.Printf("count:%d",count)
}

The result was a fixed value of 500, which was consistent with expectations.

Guess you like

Origin blog.csdn.net/feifeixiang2835/article/details/108589395