GoDasturchi
Object Pooling with sync.Pool

Object Pooling with sync.Pool

sync.Pool bilan obyektlarni qayta ishlatish

Restoranda har bir mijoz uchun yangi likopcha sotib olish o'rniga, ishlatilgan likopchalarni yuvib, qayta ishlatasiz. Bu — vaqt va resursni tejaydi. Object Pool naqshi — dasturda ham xuddi shunday: tez-tez yaratiladigan va tashlanadigan obyektlarni (masalan katta bufer) har safar noldan yaratish o'rniga, ishlatilganidan keyin "yuvib", qayta berish uchun saqlab qo'yish.

Go'da bu maqsad uchun sync.Pool mavjud. U ayniqsa xotira ajratish (allocation) qimmatga tushadigan holatlarda foydali — masalan, katta hajmdagi vaqtinchalik buferlar bilan tez-tez ishlaydigan serverlarda.

example.go
package main

import (
	"fmt"
	"sync"
)

type Buffer struct {
	data []byte
}

var pool = sync.Pool{
	New: func() interface{} {
		return &Buffer{data: make([]byte, 0, 1024)}
	},
}

func main() {
	buf := pool.Get().(*Buffer)
	buf.data = append(buf.data, []byte("salom")...)
	fmt.Println(string(buf.data))

	buf.data = buf.data[:0] // "tozalash" — foydalanishdan oldin bo'shatib qo'yish
	pool.Put(buf)

	buf2 := pool.Get().(*Buffer)
	fmt.Println(len(buf2.data)) // bo'sh, lekin xotira allaqachon ajratilgan
}

sync.Pool{New: ...} — agar to'plamda hozircha bo'sh (ishlatilmayotgan) obyekt bo'lmasa, New funksiyasi chaqirilib, yangisi yaratiladi. pool.Get() — to'plamdan bitta obyekt oladi (yo eski, yo yangi). pool.Put(buf) — ishlatib bo'lgach, obyektni qaytarib, keyingi safar boshqa kimdir foydalanishi uchun to'plamga qo'shadi.

Muhim ogohlantirish: Putdan oldin obyektni albatta "tozalash" kerak (bu yerda buf.data[:0] bilan uzunlikni nolga tushirish) — aks holda keyingi olguvchi eski, kutilmagan ma'lumotni ko'rishi mumkin. Va yana bir narsa: sync.Pooldagi obyektlar kafolatlanmagan — Go'ning axlat yig'uvchisi (garbage collector) istalgan vaqtda to'plamni bo'shatib yuborishi mumkin, shuning uchun sync.Poolni faqat vaqtinchalik, tez-tez qayta yaratiladigan obyektlar uchun ishlating, doimiy saqlash uchun emas.

>_ Exercise

sync.Pool yordamida qayta ishlatiladigan hisoblagich obyektini yasang.

  • Counter struct'i (Value int) yasang
  • sync.Pool yarating: New funksiyasi &Counter{} qaytarsin
  • pool.Get() bilan Counter oling, Value'ni 5 ga o'rnating, chop eting
  • Value'ni 0 ga qaytarib, pool.Put() bilan qaytaring, so'ng yana Get() qilib Value'ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Pool tez-tez yaratilib-tashlanadigan obyektlarni qayta ishlatib, xotira ajratish yukini kamaytiradi — lekin obyektni qaytarishdan oldin uni "tozalash" dasturchining o'z zimmasida.

NEXT UP

Singleflight Pattern

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Object Pooling with sync.Pool

sync.Pool bilan obyektlarni qayta ishlatish

Restoranda har bir mijoz uchun yangi likopcha sotib olish o'rniga, ishlatilgan likopchalarni yuvib, qayta ishlatasiz. Bu — vaqt va resursni tejaydi. Object Pool naqshi — dasturda ham xuddi shunday: tez-tez yaratiladigan va tashlanadigan obyektlarni (masalan katta bufer) har safar noldan yaratish o'rniga, ishlatilganidan keyin "yuvib", qayta berish uchun saqlab qo'yish.

Go'da bu maqsad uchun sync.Pool mavjud. U ayniqsa xotira ajratish (allocation) qimmatga tushadigan holatlarda foydali — masalan, katta hajmdagi vaqtinchalik buferlar bilan tez-tez ishlaydigan serverlarda.

example.go
package main

import (
	"fmt"
	"sync"
)

type Buffer struct {
	data []byte
}

var pool = sync.Pool{
	New: func() interface{} {
		return &Buffer{data: make([]byte, 0, 1024)}
	},
}

func main() {
	buf := pool.Get().(*Buffer)
	buf.data = append(buf.data, []byte("salom")...)
	fmt.Println(string(buf.data))

	buf.data = buf.data[:0] // "tozalash" — foydalanishdan oldin bo'shatib qo'yish
	pool.Put(buf)

	buf2 := pool.Get().(*Buffer)
	fmt.Println(len(buf2.data)) // bo'sh, lekin xotira allaqachon ajratilgan
}

sync.Pool{New: ...} — agar to'plamda hozircha bo'sh (ishlatilmayotgan) obyekt bo'lmasa, New funksiyasi chaqirilib, yangisi yaratiladi. pool.Get() — to'plamdan bitta obyekt oladi (yo eski, yo yangi). pool.Put(buf) — ishlatib bo'lgach, obyektni qaytarib, keyingi safar boshqa kimdir foydalanishi uchun to'plamga qo'shadi.

Muhim ogohlantirish: Putdan oldin obyektni albatta "tozalash" kerak (bu yerda buf.data[:0] bilan uzunlikni nolga tushirish) — aks holda keyingi olguvchi eski, kutilmagan ma'lumotni ko'rishi mumkin. Va yana bir narsa: sync.Pooldagi obyektlar kafolatlanmagan — Go'ning axlat yig'uvchisi (garbage collector) istalgan vaqtda to'plamni bo'shatib yuborishi mumkin, shuning uchun sync.Poolni faqat vaqtinchalik, tez-tez qayta yaratiladigan obyektlar uchun ishlating, doimiy saqlash uchun emas.

>_ Exercise

sync.Pool yordamida qayta ishlatiladigan hisoblagich obyektini yasang.

  • Counter struct'i (Value int) yasang
  • sync.Pool yarating: New funksiyasi &Counter{} qaytarsin
  • pool.Get() bilan Counter oling, Value'ni 5 ga o'rnating, chop eting
  • Value'ni 0 ga qaytarib, pool.Put() bilan qaytaring, so'ng yana Get() qilib Value'ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Pool tez-tez yaratilib-tashlanadigan obyektlarni qayta ishlatib, xotira ajratish yukini kamaytiradi — lekin obyektni qaytarishdan oldin uni "tozalash" dasturchining o'z zimmasida.

NEXT UP

Singleflight Pattern