Go-da bir neçə goroutine-un düzgün şəkildə necə tamamlanması?
sobes.tech Süni İntellekt
AI-dan cavab
Müxtəlif yaygın üsullar mövcuddur:
-
Kontextdən istifadə (Context): Ağac şəklində çağırışlar strukturunda əməliyyatların ləğvi üçün tövsiyə olunan yanaşmadır. Kontext ləğv siqnalını kanal vasitəsilə ötürə bilər.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d tamamlanır: %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d işləyir...\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() // Ləğv siqnalını göndəririk time.Sleep(1 * time.Second) // Gorutinaların tamamlanması üçün vaxt veririk fmt.Println("Əsas proqram tamamlandı.") } -
Kanalardan istifadə: Xüsusi kanala (məsələn, boş struktur
struct{}) siqnal göndərməklə, gorutinə tamamlanma ehtiyacını bildirə bilərsiniz.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d kanaldan tamamlanır\n", id) return default: fmt.Printf("Goroutine %d işləyir...\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) // Kanalın bağlanması tamamlanma siqnalını verir time.Sleep(1 * time.Second) // Gorutinaların tamamlanması üçün vaxt veririk fmt.Println("Əsas proqram tamamlandı.") } -
sync.WaitGroupistifadə edərək (təkcə gözləmə üçün, siqnal vermək üçün deyil):WaitGroupgorutinaların tamamlanmasını gözləmək üçün istifadə olunur, lakin özü dayandırma mexanizmi təmin etmir. Onu tez-tez kontekst və ya kanallar ilə birlikdə istifadə edirlər.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Gorutinal tamamlandıqda WaitGroup sayğacını azaldır for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d tamamlanır\n", id) return default: fmt.Printf("Goroutine %d işləyir...\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-i başlatırıq for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // Ləğv siqnalı wg.Wait() // Bütün gorutinaların tamamlanmasını gözləyirik fmt.Println("Əsas proqram tamamlandı.") }
Seçim metodu konkret istifadə halına və gorutinlərin qarşılıqlı əlaqəsinin mürəkkəbliyinə bağlıdır. Context ümumiyyətlə kaskad ləğvlər üçün üstün tutulur.