Files
notes_estom/Go/gopkg/sync/sync.go
2021-09-03 05:34:34 +08:00

110 lines
2.3 KiB
Go

// sync 主要提供原子操作、互斥锁、读写锁
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
//
// Mutex
//
m := new(sync.Mutex)
c1, c2 := 0, 0
ch := make(chan int, 200)
for i := 0; i < 100; i++ {
go click(&c1, ch)
}
for i := 0; i < 100; i++ {
go clickWithMutex(&c2, m, ch)
}
for i := 0; i < 200; i++ { // 循环阻塞等待两百次任务完成
<-ch
}
fmt.Printf("c1: %d c2:%d\n", c1, c2) // c1: 56108 c2:10000 // 在多个 goroutine 中对同一变量进行操作时,一定要加锁
// RWMutex 读写锁
c3 := 0
rwLocker := new(sync.RWMutex)
clickWithRWMutex(&c3, rwLocker, ch)
fmt.Printf("c3: %d\n", c3)
//
// Once
//
once := new(sync.Once) // 保证 func 只会执行一次
for i := 0; i < 3; i++ {
go func(i int) {
once.Do(func() {
fmt.Println("once done: ", i)
})
fmt.Println("i: ", i)
ch <- 1
}(i)
}
for i := 0; i < 3; i++ {
<-ch
}
//
// WaitGroup
//
wg := new(sync.WaitGroup)
for i := 0; i < 3; i++ {
wg.Add(1) // 添加指定个元素到 WaitGroup 中
go Process(wg, i)
}
wg.Wait() // 阻塞直到 WaitGroup 中所有任务完成
//
// 原子操作
//
var u1 uint32
atomic.AddUint32(&u1, 2) // 原子操作只针对长度固定的数据
fmt.Println(u1) // 2
fmt.Println(atomic.SwapUint32(&u1, 100)) // 2 // 返回旧数据
fmt.Println(u1) // 100
fmt.Println(atomic.LoadUint32(&u1)) // 互斥读:在读取期间,程序的其他部分无法再对变量进行读写操作
}
func clickWithRWMutex(total *int, rwLocker *sync.RWMutex, ch chan int) {
for i := 0; i < 1000; i++ {
rwLocker.Lock()
*total++
rwLocker.Unlock()
if i == 500 {
rwLocker.RLock()
fmt.Println(*total) // 501 // 只保证读,不保证写...惊不惊喜意不意外
rwLocker.RUnlock()
}
}
ch <- 1
}
func click(total *int, ch chan int) {
for i := 0; i < 1000; i++ {
*total += 1
}
ch <- 1
}
func clickWithMutex(total *int, m *sync.Mutex, ch chan int) {
for i := 0; i < 1000; i++ {
m.Lock()
*total += 1
m.Unlock()
}
ch <- 1
}
// 这里必须传入指针,对 wg 变量进行修改
func Process(wg *sync.WaitGroup, id int) {
time.Sleep(1 * time.Second)
fmt.Printf("task %d is done\n", id)
wg.Done()
}