Go Map Performansı: Büyük Veri Setlerinde Optimizasyon
Go'da map (harita) kullanırken binlerce ya da milyonlarca veri işlerken hafızada ani artışlar ve hız düşüşü yaşanabilir. Sorun çoğunlukla dinamik büyümeden ve senkronizasyon eksikliğinden gelir.
Map'i baştan doğru boyutla oluşturmak ilk adım. Go, iç kapasiteyi aşınca tüm veriye yeni yer ayırır ve eski veriyi kopyalar. Bunun yerine make(map[string]int, 100000) ile ön ayırma yaparsanız bu maliyeti büyük ölçüde azaltırsınız.
İkinci sorun eş zamanlı (concurrent) erişim. Aynı anda birden fazla goroutine map'e yazarsa program çöker. Çözüm sync.RWMutex ile okuma-yazma kilitlemesi ya da sync.Map kullanmaktır.
Burada iki yaklaşımı karşılaştıran örnek kod var:
1package main23import (4"fmt"5"sync"6"time"7)89func testRegularMap() {10m:= make(map[string]int, 1000000) // Ön ayırma11var mu sync.RWMutex12start:= time.Now()1314for i:= 0; i < 1000000; i++ {15mu.Lock()16m[fmt.Sprintf("key%d", i)] = i17mu.Unlock()18}1920fmt.Printf("RWMutex map: %v\n", time.Since(start))21}2223func testSyncMap() {24var m sync.Map25start:= time.Now()2627for i:= 0; i < 1000000; i++ {28m.Store(fmt.Sprintf("key%d", i), i)29}3031fmt.Printf("sync.Map: %v\n", time.Since(start))32}3334func main() {35testRegularMap()36testSyncMap()37}Beklenen çıktı:
1RWMutex map: 450ms2sync.Map: 280mssync.Map okuma ağırlıklı işlerde daha hızlı çalışır, çünkü okuma kilitlemesi gerektirmez. Ancak yazma yoğunsa RWMutex ile ön ayırma yapılmış normal map tercih edilebilir.
Sık yapılan hata: map'i hiç boyutlandırmadan milyonlarca veri eklemek. Bu durumda Go hafızayı 10-15 kez yeniden ayırır ve program yavaşlar. Veri sayısını önceden biliyorsanız mutlaka make(map[...], tahminiSize) kullanın.
Bir başka ipucu: çok sık erişilen veriler için sync.Map yerine local cache + periyodik senkronizasyon daha etkili olabilir. Büyük haritaları parçalara bölüp her parçaya ayrı mutex atamak da uyuşmazlığı azaltır.
5 yorum
sync Mapi denedim ama map[string]interface{} ile uğraştığım için biraz hantal oldu açıkçası RWMutex daha kontrollü geldi bana
sync Map denedin mi RWMutexten daha basit oluyor bence özellikle çok goroutinein olduğu yerlerde
ya birçok kişi bunu bilmiyor galiba ben de şaşırdım ilk defa öğrendiğimde
interface{} çok kötü ya sonra type assertion falan derdi oluyor
abi doğru ben de ilk başta mapi normal değişken gibi düşünüyordum sonra productionda bir sürü goroutine çalıştırınca program direkt patladı o zaman anladım neden lock gerektiğini