Concurrent access to maps with 'range' in Go

后端 未结 2 627

The \"Go maps in action\" entry in the Go blog states:

Maps are not safe for concurrent use: it\'s not defined what happens when you read and write t

2条回答
  •  别那么骄傲
    2020-12-16 01:18

    The unit of concurrent access for a for range loop over a map is the map. Go maps in action.

    A map is a dynamic data structure that changes for inserts, updates and deletes. Inside the Map Implementation. For example,

    The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0. For statements, The Go Programming Language Specification

    Reading a map with a for range loop with interleaved inserts, updates and deletes is unlikely to be useful.

    Lock the map:

    package main
    
    import (
        "sync"
    )
    
    var racer map[int]int
    
    var race sync.RWMutex
    
    func Reader() {
        race.RLock() // Lock map
        for k, v := range racer {
            _, _ = k, v
        }
        race.RUnlock()
    }
    
    func Write() {
        for i := 0; i < 1e6; i++ {
            race.Lock()
            racer[i/2] = i
            race.Unlock()
        }
    }
    
    func main() {
        racer = make(map[int]int)
        Write()
        go Write()
        Reader()
    }
    

    Don't lock after the read -- fatal error: concurrent map iteration and map write:

    package main
    
    import (
        "sync"
    )
    
    var racer map[int]int
    
    var race sync.RWMutex
    
    func Reader() {
        for k, v := range racer {
            race.RLock() // Lock after read
            _, _ = k, v
            race.RUnlock()
        }
    }
    
    func Write() {
        for i := 0; i < 1e6; i++ {
            race.Lock()
            racer[i/2] = i
            race.Unlock()
        }
    }
    
    func main() {
        racer = make(map[int]int)
        Write()
        go Write()
        Reader()
    }
    

    Use the Go Data Race Detector. Read Introducing the Go Race Detector.

提交回复
热议问题