Go 学习笔记11.互斥锁,读写锁,状态协程

互斥锁

互斥所 它由标准库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)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章