網頁

2022/4/29

Golang concurrent map簡單實作

Go實作一個簡單可供並行程序存取的concurrent map。


Go的map不保證執行緒安全,即當多個goroutine程序存取通個資源時會發生race condition(資源競爭)導致非預期的結果,所以執行goroutine並行程式應限制map同步存取。


範例環境:

  • Go 1.18


範例

使用sync.RWMutex的讀/寫鎖在存取package level map變數m上。

get()使用RWMutex.RLock()RWMutex.RUnLock()允許多個goroutine並行讀取。

put()使用RWMutex.Lock()RWMutex.UnLock()限制只能一個goroutine寫入。

main.go

package main

import (
    "fmt"
    "sync"
    "time"
)

var rwmu sync.RWMutex

var m = map[int]int{}

func main() {
    for i := 0; i < 10; i++ {
        go put(i, i)
        go func(k int) {
            fmt.Println(get(k))
        }(i)
    }
    time.Sleep(time.Second)
}

func get(k int) int {
    rwmu.RLock()
    defer rwmu.RUnlock()
    v, ok := m[k]
    if ok == false {
        return -1
    }
    return v
}

func put(k int, v int) {
    rwmu.Lock()
    defer rwmu.Unlock()
    m[k] = v
}

func size() int {
    rwmu.RLock()
    defer rwmu.RUnlock()
    return len(m)
}

github


測試

可用go run -race main.go確認是否有data race condition的情況。若把Mutex lock移除並執行可能發生以下錯誤

~/../go-demo$ go run -race main.go
-1
-1
-1
==================
WARNING: DATA RACE
Read at 0x00c00007e048 by goroutine 14:
  main.get()
      /../main.go:26 +0x58
  main.main.func1()
      /../main.go:17 +0x61
  main.main.func3()
      /..//main.go:18 +0x47

Previous write at 0x00c00007e048 by goroutine 13:
  main.put()
      /../main.go:36 +0x57
  main.main.func2()
      /../main.go:15 +0x47

Goroutine 14 (running) created at:
  main.main()
      /../main.go:16 +0x44

Goroutine 13 (running) created at:
  main.main()
      /../main.go:15 +0xb7
==================
...


沒有留言:

張貼留言