ProgrammingBackend Developer

Describe the mechanism of protection against data races when working with maps in Go. What guarantees exist, and why does simple work with a map in multiple goroutines without protection lead to errors?

Pass interviews with Hintsage AI assistant

Answer

In Go, maps are not thread-safe by default. If multiple goroutines simultaneously write to or read from the same map without synchronization, a data race will occur, resulting in a panic: fatal error: concurrent map read and map write or data corruption.

To work with maps safely in a concurrent environment, you need to:

  • Use sync.Mutex or sync.RWMutex primitives to protect all read and write operations.
  • Alternatively, use the sync.Map package, which is designed for high-load concurrent scenarios.
var mu sync.RWMutex m := make(map[string]int) // Writing mu.Lock() m["key"] = 1 mu.Unlock() // Reading mu.RLock() v := m["key"] mu.RUnlock() // Or sync.Map var sm sync.Map sm.Store("key", 1) v, _ := sm.Load("key")

Trick Question

Why is simultaneous reading and writing from different goroutines to a map in Go so dangerous, if a map is a built-in type?

Answer: In Go, the built-in map type does not provide synchronization. Concurrent access to a map from multiple goroutines does not just yield incorrect values; it can lead to program crashes. Even simultaneous reading and writing (when there are no overlapping keys!) can cause a fatal error. This differs from some other languages where collections are "tolerant" of concurrent accesses.

Examples of real errors due to ignorance of the topic


Story

In a real project, a developer used a global map for caching data. The service worked steadily in tests, but during load tests and in production, it began to crash with the error fatal error: concurrent map read and map write. The cause was parallel access to the map from different HTTP requests without using Mutex.


Story

In a Go web application, one programmer decided to improve performance and used a regular map as a connection pool, assuming that multithreading was handled by the framework. During a sudden traffic surge, the service began to crash without an obvious reason: due to the race, data in the map got corrupted, leading to panics.


Story

In an internal Go service, the application used a map to collect statistics "on the fly," thinking that the main operation was solely for writing. In reality, another part of the code occasionally requested data for report generation, leading to elusive crashes occurring only once a day — right when the statistics were triggered. Analysis showed that reads and writes overlapped without any locking.