This is the 7th day of my participation in Gwen Challenge
Resource competition: When multiple Goroutines compete for the same block of memory, there is no way to know who will access it first and the outcome is unpredictable.
Therefore, we need to ensure that shared memory resources are operated by only one coroutine execution.
sync.Mutex
Mutex: Only one coroutine executes a piece of code at a time, and all other coroutines wait for the coroutine to finish executing.
// Define a synchronization lock
var mutex sync.Mutex
// lock a code segment
mutex.Lock() / / lock. mutex.Unlock()/ / unlock
Copy the code
A locked section of code can be called a critical section.
In synchronous programming, a critical section is a program segment that accesses a shared resource that cannot be accessed by more than one coroutine simultaneously. When a coroutine is in a critical section, other coroutines must wait, so as to ensure the concurrency safety in the critical section.
Mutex locks must be followed by Unlock, which is paired with each other, so you can finally release the Lock by using the defer statement
defer mutex.Unlock()
Copy the code
sync.RWMutex
In some business scenarios, when a variable is written and read by another coroutine, an expired value is read, resulting in dirty reads. So, to solve this problem of resource contention, sync.mutex is used to control that the other coroutine must wait for the write operation to complete before it can read.
However, performance problems can also arise when multiple coroutines compete for resources with simultaneous reads and writes
Analysis of three special scenarios of reading and writing
- Write Operation A simultaneous read operation may cause dirty data to be read
- When a read operation is performed at the same time as a write operation, the result is unpredictable
- Read operations are also read by other coroutines without concurrency security
Sync. RWMutex reads and writes locks to improve performance. Multiple coroutines can read at the same time without waiting for each other
var mutex sync.RWMutex
mutex.RLock()
defer mutex.RUnlock()
Copy the code
sync.WaitGroup
What happens if, in the main function main(), 100 coroutines are started and the main function returns prematurely before 100 coroutines have been executed?
When the main function returns, the entire program exits. It is possible that the subcoroutine has not completed execution, resulting in unpredictable results. To resolve this situation, we should ensure that all coroutines are executed before exiting the program.
Sync.waitgroup addresses this situation.
Usage:
- Declare a sync.waitgroup and set the counter to as many coroutines as you can with the Add method
- The Done method is called after each coroutine, decrement the counter by one
- Finally, the Wait method is called to Wait until the counter value is 0, indicating that all coroutines have been executed
var wg sync.WaitGroup
go func(a){
defer wg.Done() // When a coroutine ends, the counter decays by 1. }...// Wait until the counter is 0
wg.Wait()
Copy the code
Usage scenario: Multiple coroutines can work together to improve efficiency. For example, when a file is downloaded, it is divided into several coroutines, and the entire file is not downloaded until all coroutines have downloaded.
sync.Once
Requirement scenario: Make the code run only once
- Creates a singleton of an object
- Resources that are loaded only once
An example comes with the Go language
1. func main(a) {
2. doOnce()
3. }
4. func doOnce(a) {
5. var once sync.Once
6. onceBody := func(a) {
7. fmt.Println("Only once")
8. }
9. // Wait for the coroutine to finish executing
10. done := make(chan bool)
11. // Start 10 coroutines to execute once.Do(onceBody)
12. for i := 0; i < 10; i++ {
13. go func(a) {
14. // Pass the function to be executed as an argument to the once.Do method
15. once.Do(onceBody)
16. done <- true
17.} ()18. }
19. for i := 0; i < 10; i++ {
20. <-done
21. }
22. }
Copy the code
Ten coroutines are started to execute onceBody, but the once.do () method is used, so the onceBody function is executed only once
sync.NewCond
It has the function of blocking coroutine and waking up coroutine.
var cond = sync.NewCond(&sync.Mutex)
Copy the code
- The Wait() method, which blocks the current coroutine until it is awakened by another coroutine calling the Broadcase or Signal methods, must be used with a lock
- Signal to wake up the coroutine with the longest waiting time
- Broadcast wakes up all waiting coroutines
Note: Before calling Signal and Broadcast, ensure that the target coroutine is in Wait blocking state
sync.Map
- Store: Stores a pair of key-values.
- Load: Obtains the value of the key and determines whether the key exists.
- LoadOrStore: If the value corresponding to the key exists, this value is returned. If not, store the corresponding value.
- Delete: deletes a key-value pair.
- Range: Iterate over sync.Map with the same effect as for Range