SoFunction
Updated on 2025-03-03

Solutions to the thread safety problem of Golang's Map

Preface

In Golang programming, map is a commonly used data structure used to store key-value pairs. However, Golang's map is thread-insecure when accessed concurrently. If multiple goroutines read and write the same map at the same time, it may cause data race and program crashes. This article will introduce in detail the thread insecurity of maps in Golang and provide some solutions to help developers use maps correctly in concurrent programming.

1. Scene introduction

1. What is thread insecure

Thread insecure refers to the fact that in a multi-thread (or multiple goroutine) environment, when multiple threads access and modify shared data at the same time, it may cause data inconsistency or program crashes. For Golang's map, this will happen if multiple goroutines read and write the same map at the same time without an appropriate synchronization mechanism.

2. Map is thread-insecure

At the same time, it is not safe to read and write to the same map by two goroutines. For example:

The number of map buckets is 4, that is, B=2. At this time, goroutine1 is inserted into key1, goroutine2 is used to read key2. The following process may occur:

  • 1.goroutine2 calculates the hash value of key2, B=2, and determines the bucket number to 1.
  • 2.goroutine1 Add key1 to trigger the expansion condition.
  • =B+1=3, buckets data is migrated to oldbuckets.
  • 4.goroutine2 traversed from bucket 1 and failed to get data.

3. Examples of thread insecure

Here is a simple example showing the errors that multiple goroutines can be read and written simultaneously without a synchronization mechanism:

package main

import (
    "fmt"
    "sync"
)

func main() {
    m := make(map[int]int)
    var wg 

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            m[i] = i
        }(i)
    }

    ()
    (m)
}

2. Use of thread-safe maps

1. Use Synchronization

To avoid data competition, synchronization can be used. A lock mechanism is provided to ensure that only one goroutine can access the map at the same time.

Example:

package main

import (
    "fmt"
    "sync"
)

func main() {
    m := make(map[int]int)
    var mu 
    var wg 

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            ()
            m[i] = i
            ()
        }(i)
    }

    ()
    (m)
}

In this example, using () and () ensures that only one goroutine can access the map at a time, thus avoiding data race.

2. Use read and write locks

If the read operations are much more than the write operations, you can use the read and write lock. Read locks and write locks are provided, allowing multiple goroutines to perform read operations at the same time, but write operations are still mutually exclusive.

Example:

package main

import (
    "fmt"
    "sync"
)

func main() {
    m := make(map[int]int)
    var mu 
    var wg 

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            ()
            m[i] = i
            ()
        }(i)
    }

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            ()
            (m[i])
            ()
        }(i)
    }

    ()
}

In this example, use () and () for read operations and use () and () for write operations to improve the efficiency of concurrent reads.

3. Use

The Golang standard library provides , it is a concurrent and secure map implementation suitable for scenarios where high concurrent access is required. Atomic operations are provided to avoid the complexity of manual locking.

Example:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var m 
    var wg 

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            (i, i)
        }(i)
    }

    for i := 0; i < 10; i++ {
        (1)
        go func(i int) {
            defer ()
            value, _ := (i)
            (value)
        }(i)
    }

    ()
}

In this example, using () for write operations and using () for read operations, concurrency security has been implemented internally.

3. Summary

Maps in Golang are thread-insecure when accessed concurrently, and if not processed synchronously, it may cause data race and program crashes. This article describes several solutions, including using , and . I hope that through the introduction of this article, readers can better understand the thread insecurity of maps in Golang and correctly use maps for concurrent programming in actual projects.

The above is the detailed content about the solution to the thread safety problem of Golang Map. For more information about the thread safety problem of Golang Map, please pay attention to my other related articles!