互斥锁
互斥所 它由标准库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)
}