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