Oldingi darsning davomi
select darsida ikkita kanal orasidan tanlash va default holatini ko'rgan edik. Bu darsda selectning amaliyotda eng ko'p ishlatiladigan ikki qo'llanilishini ko'ramiz: timeout (vaqt chegarasi) va bloklanmaydigan (non-blocking) yuborish/qabul qilish.
time.After()Ba'zan biror amal (masalan, tarmoq so'rovi) juda uzoq davom etib ketishi mumkin, va biz uni abadiy kutishni xohlamaymiz. Buning uchun selectni time.After() bilan birga ishlatamiz:
package main
import (
"fmt"
"time"
)
func slowOperation(ch chan<- string) {
time.Sleep(2 * time.Second) // 2 soniya davom etadigan "sekin" amal
ch <- "natija tayyor"
}
func main() {
ch := make(chan string)
go slowOperation(ch)
select {
case result := <-ch:
fmt.Println(result)
case <-time.After(500 * time.Millisecond):
// agar 500ms ichida ch dan hech narsa kelmasa, shu holat ishga tushadi
fmt.Println("Vaqt tugadi! Amal juda uzoq davom etyapti")
}
}
Natija:
Vaqt tugadi! Amal juda uzoq davom etyapti
slowOperation() 2 soniyadan keyin javob bergan bo'lardi, lekin time.After(500 * time.Millisecond) atigi 500 millisekunddan keyin "signal" beradi, va select qaysi holat birinchi tayyor bo'lsa, o'shani tanlaydi. Natijada dastur 2 soniya kutib o'tirmasdan, tezroq "vaqt tugadi" deb javob qaytaradi.
[!IMPORTANT]
time.After(d)har chaqirilganda yangi kanal va yangi timer yaratadi. Agarselectsikl ichida ko'p marta ishlatilsa, bu ortiqcha xotira sarflashi mumkin. Bunday hollarda bittatime.NewTimer()yaratib, uni qayta-qaytaReset()qilish tavsiya etiladi — lekin oddiy, bir martalik timeout holatlari uchuntime.After()to'liq yetarli va eng ko'p ishlatiladigan usul.
Bu pattern, ayniqsa, context.WithTimeout() bilan birga (Standard Library bo'limidagi context darsida ko'rgan edik) tashqi API so'rovlariga vaqt chegarasi qo'yishda juda keng qo'llaniladi.
select + defaultOddiy <-ch agar kanalda hech narsa bo'lmasa, kutadi. Ba'zan esa "agar hozir tayyor ma'lumot bo'lsa olib qol, bo'lmasa darhol davom et" degan xatti-harakat kerak bo'ladi:
package main
import "fmt"
func main() {
ch := make(chan int)
select {
case v := <-ch:
fmt.Println("Qabul qilindi:", v)
default:
// ch da hech narsa yo'q, lekin dastur kutib QOLMAYDI
fmt.Println("Hech narsa yo'q, davom etamiz")
}
}
Natija:
Hech narsa yo'q, davom etamiz
Xuddi shu pattern yuborish uchun ham ishlaydi — agar hech kim qabul qilishga tayyor bo'lmasa, yuborish shunchaki "o'tkazib yuboriladi":
package main
import "fmt"
func main() {
ch := make(chan int) // hech kim o'qimayapti
select {
case ch <- 1:
fmt.Println("Yuborildi")
default:
fmt.Println("Hech kim qabul qilmayapti, yuborilmadi")
}
}
Natija:
Hech kim qabul qilmayapti, yuborilmadi
Bu, masalan, log yozuvlarini "agar imkoni bo'lsa" jo'natish, aks holda uni shunchaki tashlab yuborish (log kanali to'lib ketganda dasturni sekinlashtirib qo'ymaslik) kabi hollarda foydalaniladi.
| Vazifa | Pattern |
|---|---|
| Amalga vaqt chegarasi qo'yish | select { case <-ch: ...; case <-time.After(d): ... } |
| Kanalda ma'lumot bor-yo'qligini kutmasdan tekshirish | select { case v := <-ch: ...; default: ... } |
| Band bo'lsa yuborishni o'tkazib yuborish | select { case ch <- v: ...; default: ... } |
[!NOTE]
selectichidagidefaultholati mavjud bo'lsa,selecthech qachon kutmaydi — agar boshqa hech qaysicasedarhol tayyor bo'lmasa,defaultzudlik bilan ishga tushadi.defaultyozilmasa esa,selectkamida bittacasetayyor bo'lguncha (yokitime.Afterkabi vaqt asosidagi holat ishga tushguncha) kutadi.