Tommy

Tommy

写代码是热爱,但也是生活 !
github

Go mapはなぜスレッドセーフでないのですか?

map はデフォルトで並行安全ではなく、map に対して並行して読み書きを行うと、プログラムは panic します。その理由は以下の通りです:

Go の公式は長時間の議論の末、Go の map は典型的な使用シーン(複数の goroutine から安全にアクセスする必要がない)に適応すべきであり、一部のケース(並行アクセス)のために大多数のプログラムがロックコスト(パフォーマンス)を負うことを決定し、サポートしないことにしました。

シーン:2 つのゴルーチンが同時に読み書きすると、以下のプログラムで致命的なエラーが発生します:fatal error: concurrent map writes

package main
import (
    "fmt"
    "time"
)
func main() {
    s := make(map[int]int)
    for i := 0; i < 100; i++ {
        go func(i int) {
            s[i] = i
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            fmt.Printf("map第%d个元素值是%d\n", i, s[i])
        }(i)
    }
    time.Sleep(1 * time.Second)
}

map をスレッド安全に実現するには、2 つの方法があります:

方法一:読み書きロックを使用する map + sync.RWMutex

package main
import (
    "fmt"
    "sync"
    "time"
)
func main() {
    var lock sync.RWMutex
    s := make(map[int]int)
    for i := 0; i < 100; i++ {
        go func(i int) {
            lock.Lock()
            s[i] = i
            lock.Unlock()
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            lock.RLock()
            fmt.Printf("map第%d个元素值是%d\n", i, s[i])
            lock.RUnlock()
        }(i)
    }
    time.Sleep(1 * time.Second)
}

方法二:Go が提供する sync.Map を使用する

package main
import (
    "fmt"
    "sync"
    "time"
)
func main() {
    var m sync.Map
    for i := 0; i < 100; i++ {
        go func(i int) {
            m.Store(i, i)
        }(i)
    }
    for i := 0; i < 100; i++ {
        go func(i int) {
            v, ok := m.Load(i)
            fmt.Printf("Load: %v, %v\n", v, ok)
        }(i)
    }
    time.Sleep(1 * time.Second)
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。