互斥鎖
互斥所 它由標準庫sync.Mutex來表示 方法有 Lock和Unlock
package main
import (
"fmt"
"time"
)
func printer(str string) {
for _, data := range str {
time.Sleep(time.Millisecond*100)
fmt.Printf("%c", data)
}
fmt.Println()
}
func print1() {
printer("hello")
}
func print2() {
printer("world")
}
func main() {
go print1()
print2()
time.Sleep(time.Second *2 )
}
輸出結果爲
hwoelrllo
d
我們希望是
hello
world
這時候可以使用互斥鎖了
package main
import (
"fmt"
"time"
"sync"
)
// 創建互斥鎖對象
var mutex sync.Mutex
func printer(str string) {
mutex.Lock() //上鎖
// defer mut.Unlock() 這樣皆可以,再執行結束後解鎖,就不需要額外解鎖了
for _, data := range str {
time.Sleep(time.Millisecond*100)
fmt.Printf("%c", data)
}
fmt.Println()
mutex.Unlock() // 解鎖
}
func print1() {
printer("hello")
}
func print2() {
printer("world")
}
func main() {
go print1()
print2()
time.Sleep(time.Second *2 )
}
讀寫鎖
上面的互斥所,資源同時只能有一個協程訪問
但是,當我們取讀數據的時候,數據是不會變得,可以隨意的訪問
只有修改,寫操作的時候,纔會出現問題,這樣讀寫鎖就出現了
var mutex sync.RWMutex
package main
import (
"sync"
"math/rand"
"time"
"fmt"
)
var count int
var mutex sync.RWMutex
func write(n int) {
mutex.Lock()
rand.Seed(time.Now().UnixNano())
fmt.Printf("寫 goroutine %d 正在寫數據...\n", n)
// time.Sleep(time.Second)
num := rand.Intn(500)
count = num
fmt.Printf("寫 goroutine %d 寫數據結束,寫入新值 %d\n", n, num)
mutex.Unlock()
}
func read(n int) {
mutex.RLock()
fmt.Printf("讀 goroutine %d 正在讀取數據...\n", n)
//time.Sleep(time.Millisecond*500)
num := count
fmt.Printf("讀 goroutine %d 讀取數據結束,讀到 %d\n", n, num)
mutex.RUnlock()
}
func main() {
// 500個協程讀
for i := 0; i < 500; i++ {
go read(i + 1)
}
// 10個協程寫
for i := 0; i < 10; i++ {
go write(i + 1)
}
time.Sleep(time.Second*5)
}
go狀態協程
package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)
// 創建 讀 寫 結構體
type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main() {
// 累加次數
var ops int64
// 讀寫結構體定義
reads := make(chan *readOp)
writes := make(chan *writeOp)
go func() {
// 協程裏面定義map字典,協程內私有的
var state = make(map[int]int)
for {
select {
case read := <-reads:
// 接收到讀操作,將state[key]返回
read.resp <- state[read.key]
case write := <-writes:
// 接收到寫操作,將數據寫入到state中
state[write.key] = write.val
write.resp <- true
}
}
}()
// 讀,100個協程
for r := 0; r < 100; r++ {
go func() {
for {
//創建讀結構體對象
read := &readOp{
key: rand.Intn(5),
resp: make(chan int)}
//請求讀操作
reads <- read
// 等待返回
<-read.resp
// 累加1
atomic.AddInt64(&ops, 1)
}
}()
}
// 寫 10個協程
for w := 0; w < 10; w++ {
go func() {
for {
// 創建寫結構體對象
write := &writeOp{
key: rand.Intn(5),
val: rand.Intn(100),
resp: make(chan bool)}
// 請求寫操作
writes <- write
// 等待返回
<-write.resp
// 累加1
atomic.AddInt64(&ops, 1)
}
}()
}
// 讓 Go 協程們跑 1s。
time.Sleep(time.Second)
// 最後,獲取並報告 `ops` 值。
opsFinal := atomic.LoadInt64(&ops)
fmt.Println("ops:", opsFinal)
}