Go'da bir nechta goroutine'larni qanday to'g'ri yakunlash mumkin?
sobes.tech AI
AIdan javob
Odatda keng tarqalgan usullar mavjud:
-
Kontekstdan foydalanish (Context): Chaqiriqlar daraxti tuzilmasida operatsiyalarni bekor qilish uchun tavsiya etilgan yondashuv. Kontekst kanal orqali bekor qilish signalini uzatishi mumkin.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d yakunlanmoqda: %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d ishlamoqda...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) go worker(ctx, 1) go worker(ctx, 2) time.Sleep(3 * time.Second) cancel() // Bekor qilish signalini yuborish time.Sleep(1 * time.Second) // Goroutine'lar tugashini kutish fmt.Println("Asosiy dastur yakunlandi.") } -
Kanalardan foydalanish: Maxsus kanal orqali (masalan, bo'sh struktura
struct{}) signal yuborish orqali goroutine'ga yakunlash kerakligini bildirish mumkin.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d kanal orqali yakunlanmoqda\n", id) return default: fmt.Printf("Goroutine %d ishlamoqda...\n", id) time.Sleep(1 * time.Second) } } } func main() { stopChan := make(chan struct{}) go worker(stopChan, 1) go worker(stopChan, 2) time.Sleep(3 * time.Second) close(stopChan) // Kanalni yopish yakunlash signalini beradi time.Sleep(1 * time.Second) // Goroutine'lar tugashini kutish fmt.Println("Asosiy dastur yakunlandi.") } -
sync.WaitGroupdan foydalanish (tugash uchun kutish, signal berish uchun emas):WaitGroupbir guruh goroutine'larning tugashini kutish uchun ishlatiladi, lekin o'z-o'zidan to'xtash mexanizmi taqdim etmaydi. Ko'pincha kontekstlar yoki kanallar bilan birga ishlatiladi.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Goroutine tugagach, hisoblagichni kamaytiradi for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d yakunlanmoqda\n", id) return default: fmt.Printf("Goroutine %d ishlamoqda...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup numWorkers := 2 wg.Add(numWorkers) // WaitGroup ni boshlash for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // Bekor qilish signali wg.Wait() // Barcha goroutine'larning tugashini kutish fmt.Println("Asosiy dastur yakunlandi.") }
Usul tanlovi aniq foydalanish holatiga va goroutine'lar o'rtasidagi murakkablikka bog'liq. Kontekst odatda ketma-ket bekor qilishlar uchun afzalroq.