In Go sind Maps standardmäßig nicht threadsicher. Wenn mehrere Goroutinen gleichzeitig in dieselbe Map schreiben oder lesen, ohne synchronisiert zu sein, tritt ein Data Race auf, das zu einem Panic-Zustand fatal error: concurrent map read and map write oder zu beschädigten Daten führen kann.
Für einen threadsicheren Umgang mit Maps ist es notwendig:
sync.Map zu verwenden, das für hochbelastete konkurrierende Szenarien gedacht ist.var mu sync.RWMutex m := make(map[string]int) // Schreiben mu.Lock() m["key"] = 1 mu.Unlock() // Lesen mu.RLock() v := m["key"] mu.RUnlock() // Oder sync.Map var sm sync.Map sm.Store("key", 1) v, _ := sm.Load("key")
Warum ist das gleichzeitige Lesen und Schreiben aus verschiedenen Goroutinen in einer Map in Go so gefährlich, auch wenn Map ein eingebauter Typ ist?
Antwort: In Go bietet der eingebaute Typ Map keine Synchronisation. Der gleichzeitige Zugriff auf eine Map aus mehreren Goroutinen führt nicht nur zu inkorrekten Werten, sondern kann auch zu einem Absturz des Programms führen. Selbst gleichzeitiges Lesen und Schreiben (wenn keine überlappenden Schlüssel vorhanden sind!) kann einen fatalen Fehler verursachen. Dies unterscheidet sich von einigen anderen Programmiersprachen, in denen Sammlungen „tolerant“ für konkurrierende Zugriffe sind.
Geschichte
In einem realen Projekt verwendete ein Entwickler eine globale Map, um Daten zwischenzuspeichern. Der Dienst funktionierte stabil in Tests, fiel jedoch bei Lasttests und in der Produktion mit der Fehlermeldung fatal error: concurrent map read and map write. Der Grund war der parallele Zugriff auf die Map aus verschiedenen HTTP-Anfragen ohne Verwendung eines Mutex.
Geschichte
In einer Go-Webanwendung beschloss ein Programmierer, die Leistung zu verbessern und verwendete eine normale Map als Verbindungs-Pool, in der Annahme, dass die Multithreading-Fähigen vom Framework bereitgestellt wurden. Bei plötzlichem Traffic-Anstieg begann der Dienst ohne ersichtlichen Grund abzustürzen: Aufgrund des Data Races wurden die Daten in der Map beschädigt, was zu Paniken führte.
Geschichte
In einem internen Go-Dienst verwendete die Anwendung eine Map zur Sammlung von Statistiken „in Echtzeit“, in der Annahme, dass hauptsächlich Schreibzugriffe stattfanden. Tatsächlich fragten jedoch andere Teile des Codes regelmäßig Daten für die Erstellung von Berichten ab, was zu schwer nachvollziehbaren Abstürzen nur einmal täglich führte – genau dann, wenn die Statistiken ausgelöst wurden. Die Analyse ergab, dass Lese- und Schreibzugriffe ohne jede Sperre überlappten.