GoDasturchi
sync.Map Deep Dive

sync.Map Deep Dive

sync.Map'ga chuqur nazar

Har safar Mutex bilan qo'lda o'rab qo'yish o'rniga, agar sizga faqat xavfsiz xarita (map) kerak bo'lsa, standart kutubxonada allaqachon tayyor yechim bor: sync.Map. U — bir nechta goroutine bir vaqtda ishlatishi mumkin bo'lgan, ichida o'zining himoyasi ("kalit"i) allaqachon o'rnatilgan xarita.

example.go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map
	var wg sync.WaitGroup

	for i := 0; i < 50; i++ {
		wg.Add(1)
		go func(n int) {
			defer wg.Done()
			m.Store(n, n*n)
		}(i)
	}
	wg.Wait()

	v, ok := m.Load(7)
	fmt.Println(v, ok)
}

Oddiy map[int]int o'rniga sync.Map ishlatilgan, va u odatdagi m[key] = value yoki m[key] sintaksisini QABUL QILMAYDI — buning o'rniga Store(kalit, qiymat) va Load(kalit) metodlari ishlatiladi. Load esa mapdagi kabi ikkita qiymat qaytaradi: qiymatning o'zi va uning haqiqatan mavjudligini bildiruvchi bool.

Muhim savol: nega har doim sync.Map ishlatmaymiz, agar u xavfsiz bo'lsa? Chunki uning ichki tuzilishi ko'p o'qish, kam yozish holatlariga moslashtirilgan (masalan, konfiguratsiya keshini saqlash). Agar sizda ko'p yozish bo'lsa, oddiy map + sync.Mutex odatda tezroq va soddaroq ishlaydi. sync.Mapni "har doim yaxshiroq" emas, balki "aniq bir vaziyat uchun maxsus vosita" deb bilish kerak.

>_ Exercise

sync.Map bilan konkurrent sanoq (counter) yasang.

  • sync.Map ishlatib, 20 ta goroutine "visits" kalitini LoadOrStore/Store orqali oshiring (soddalik uchun mu bilan himoyalangan oddiy int hisoblagichdan sync.Map orqali o'qib-yozing)
  • yakunida m.Load("visits") natijasini chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Map — ko'p o'qish/kam yozish holatlari uchun maxsus, tayyor xavfsiz xarita; lekin "o'qib-o'zgartirib-yozish" kabi ketma-ket amallar uchun baribir qo'shimcha sinxronlash (Mutex) kerak bo'lishi mumkin.

NEXT UP

Atomic Operations

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

sync.Map Deep Dive

sync.Map'ga chuqur nazar

Har safar Mutex bilan qo'lda o'rab qo'yish o'rniga, agar sizga faqat xavfsiz xarita (map) kerak bo'lsa, standart kutubxonada allaqachon tayyor yechim bor: sync.Map. U — bir nechta goroutine bir vaqtda ishlatishi mumkin bo'lgan, ichida o'zining himoyasi ("kalit"i) allaqachon o'rnatilgan xarita.

example.go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map
	var wg sync.WaitGroup

	for i := 0; i < 50; i++ {
		wg.Add(1)
		go func(n int) {
			defer wg.Done()
			m.Store(n, n*n)
		}(i)
	}
	wg.Wait()

	v, ok := m.Load(7)
	fmt.Println(v, ok)
}

Oddiy map[int]int o'rniga sync.Map ishlatilgan, va u odatdagi m[key] = value yoki m[key] sintaksisini QABUL QILMAYDI — buning o'rniga Store(kalit, qiymat) va Load(kalit) metodlari ishlatiladi. Load esa mapdagi kabi ikkita qiymat qaytaradi: qiymatning o'zi va uning haqiqatan mavjudligini bildiruvchi bool.

Muhim savol: nega har doim sync.Map ishlatmaymiz, agar u xavfsiz bo'lsa? Chunki uning ichki tuzilishi ko'p o'qish, kam yozish holatlariga moslashtirilgan (masalan, konfiguratsiya keshini saqlash). Agar sizda ko'p yozish bo'lsa, oddiy map + sync.Mutex odatda tezroq va soddaroq ishlaydi. sync.Mapni "har doim yaxshiroq" emas, balki "aniq bir vaziyat uchun maxsus vosita" deb bilish kerak.

>_ Exercise

sync.Map bilan konkurrent sanoq (counter) yasang.

  • sync.Map ishlatib, 20 ta goroutine "visits" kalitini LoadOrStore/Store orqali oshiring (soddalik uchun mu bilan himoyalangan oddiy int hisoblagichdan sync.Map orqali o'qib-yozing)
  • yakunida m.Load("visits") natijasini chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Map — ko'p o'qish/kam yozish holatlari uchun maxsus, tayyor xavfsiz xarita; lekin "o'qib-o'zgartirib-yozish" kabi ketma-ket amallar uchun baribir qo'shimcha sinxronlash (Mutex) kerak bo'lishi mumkin.

NEXT UP

Atomic Operations