context paketi
context — uzoq davom etadigan amallarni (masalan, tarmoq so'rovi, ma'lumotlar bazasiga murojaat) bekor qilish, ularga vaqt chegarasi (timeout) qo'yish va goroutine'lar orasida so'rovga tegishli ma'lumotni uzatish uchun ishlatiladigan standart paket.
Ayniqsa server dasturlarida juda muhim: masalan, foydalanuvchi brauzerni yopib qo'ysa yoki so'rov juda uzoq davom etsa, context yordamida server ortiqcha ishlashni to'xtatib, resurslarni bo'shatishi mumkin.
import "context"
context.Background()Har qanday context zanjiri **context.Background()**dan boshlanadi — bu "bo'sh", hech narsaga bog'lanmagan context:
ctx := context.Background()
Odatda bu main() funksiyasida yoki eng yuqori darajadagi so'rov ishlov beruvchisida ishlatiladi, so'ngra undan boshqa maxsus context'lar "hosil qilinadi".
WithTimeout()Amalning ma'lum vaqtdan ko'p davom etishiga yo'l qo'ymaslik uchun context.WithTimeout() ishlatiladi:
package main
import (
"context"
"fmt"
"time"
)
// vaqt talab qiladigan "sekin" amalni simulyatsiya qilamiz
func slowOperation(ctx context.Context, duration time.Duration) error {
select {
case <-time.After(duration): // amal shuncha vaqtdan keyin tugaydi
fmt.Println("Amal muvaffaqiyatli tugadi")
return nil
case <-ctx.Done(): // yoki context muddati tugasa/bekor qilinsa
return ctx.Err()
}
}
func main() {
// 100 millisekunddan ko'p kutmaydigan context yaratamiz
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() // resurslarni bo'shatish uchun har doim chaqirilishi shart!
// lekin amalning o'zi 500ms talab qiladi — demak, u tugamasdan bekor qilinadi
err := slowOperation(ctx, 500*time.Millisecond)
fmt.Println(err)
}
Natija:
context deadline exceeded
[!IMPORTANT]
WithTimeout()(va boshqaWith...()funksiyalari) har doimcancelfunksiyasini ham qaytaradi. Uni ishlatilmagan taqdirda hamdefer cancel()orqali chaqirish shart — aks holda context bilan bog'liq ichki resurslar vaqtidan oldin bo'shatilmay, "sizib chiqishi" (leak) mumkin.
WithCancel()Ba'zan amalni aniq vaqt bo'yicha emas, balki boshqa bir hodisaga (masalan, foydalanuvchi "bekor qilish" tugmasini bosganda) qarab to'xtatish kerak bo'ladi:
package main
import (
"context"
"fmt"
"time"
)
func slowOperation(ctx context.Context, duration time.Duration) error {
select {
case <-time.After(duration):
fmt.Println("Amal muvaffaqiyatli tugadi")
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
// 50ms dan keyin amalni "tashqaridan" bekor qilamiz
go func() {
time.Sleep(50 * time.Millisecond)
cancel()
}()
err := slowOperation(ctx, 500*time.Millisecond)
fmt.Println(err)
}
Natija:
context canceled
ctx.Err() qaysi sababdan to'xtatilganini aniq bildiradi: muddat tugagan bo'lsa — context deadline exceeded, qo'lda bekor qilingan bo'lsa — context canceled.
WithValue()context.WithValue() orqali goroutine'lar zanjiri bo'ylab qo'shimcha ma'lumot (masalan, foydalanuvchi ID'si yoki so'rov identifikatori) uzatish mumkin:
package main
import (
"context"
"fmt"
)
// maxsus tur — oddiy string yoki int kalitlar boshqa paketlar bilan
// to'qnashib qolishining oldini olish uchun tavsiya etiladi
type contextKey string
func main() {
ctx := context.WithValue(context.Background(), contextKey("userID"), 42)
fmt.Println(ctx.Value(contextKey("userID")))
}
Natija:
42
[!WARNING]
context.WithValue()ni faqat so'rovga tegishli, ixtiyoriy ma'lumotlar (masalan, so'rov ID'si, autentifikatsiya ma'lumoti) uchun ishlating. Uni funksiyalarga oddiy parametr sifatida berilishi kerak bo'lgan ma'lumotlarni (masalan, funksiya hisoblashi uchun zarur bo'lgan qiymatlarni) "yashirincha" uzatish uchun ishlatish yomon amaliyot hisoblanadi — bu kodni o'qishni qiyinlashtiradi.
context HTTP serverlarda juda muhimAmaliyotda context eng ko'p HTTP so'rovlar bilan ishlashda uchraydi. Har bir kelgan so'rov o'z contextiga ega bo'ladi (r.Context()), va agar foydalanuvchi ulanishni uzsa (masalan, brauzer sahifasini yopsa), bu context avtomatik bekor qilinadi:
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// uzoq davom etadigan amalga shu contextni uzatamiz
err := slowDatabaseQuery(ctx)
if err != nil {
// agar foydalanuvchi allaqachon ulanishni uzgan bo'lsa,
// serverimiz ortiqcha ishlamay, darhol to'xtaydi
fmt.Println("So'rov bekor qilindi yoki xato:", err)
return
}
}
Bu usul serverning resurslarini behuda sarflamasligini ta'minlaydi — agar hech kim javobni kutmayotgan bo'lsa, server ham ishlashni davom ettirmaydi.
| Vazifa | Funksiya |
|---|---|
| Boshlang'ich context | context.Background() |
| Vaqt chegarasi qo'yish | context.WithTimeout(parent, davomiylik) |
| Aniq muddat qo'yish (masalan, "soat 18:00gacha") | context.WithDeadline(parent, vaqt) |
| Qo'lda bekor qilish imkoniyati | context.WithCancel(parent) |
| So'rovga tegishli ma'lumot uzatish | context.WithValue(parent, kalit, qiymat) |
| Bekor qilingan/tugaganini tekshirish | ctx.Done() / ctx.Err() |
[!NOTE] Amaliy qoida: agar funksiyangiz tarmoq so'rovi yuborsa, ma'lumotlar bazasiga murojaat qilsa yoki umuman uzoq davom etishi mumkin bo'lsa — unga birinchi parametr sifatida
ctx context.Contextqabul qilishni odat qiling. Bu Go community'sida keng qabul qilingan konvensiya.