Go'da birden fazla goroutine'un nasıl düzgün şekilde tamamlanacağı?
sobes.tech yapay zeka
AI'dan gelen yanıt
Bazı yaygın yöntemler şunlardır:
-
Bağlamın (Context) kullanımı: Çağrı ağaç yapısındaki işlemleri iptal etmek için önerilen yaklaşımdır. Bağlam, bir kanal aracılığıyla iptal sinyali iletebilir.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d sona eriyor: %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d çalışıyor...\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() // İptal sinyali gönderilir time.Sleep(1 * time.Second) // Goroutine'lerin bitmesini bekliyoruz fmt.Println("Ana program sona erdi.") } -
Kanalların kullanımı: Belirli bir kanal aracılığıyla (örneğin, boş bir yapı
struct{}) sinyal göndererek, goroutine'nin sona ermesi gerektiği bildirilir.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d kanal ile sona eriyor\n", id) return default: fmt.Printf("Goroutine %d çalışıyor...\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 kapatılması sona erme sinyali verir time.Sleep(1 * time.Second) // Goroutine'lerin bitmesini bekliyoruz fmt.Println("Ana program sona erdi.") } -
sync.WaitGroupkullanımı (beklemek için, sinyal vermek için değil):WaitGroup, bir grup goroutine'nin tamamlanmasını beklemek için kullanılır, ancak durdurma mekanizması sağlamaz. Genellikle bağlamlar veya kanallar ile birlikte kullanılır.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Goroutine tamamlandığında sayacı azaltır for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d sona eriyor\n", id) return default: fmt.Printf("Goroutine %d çalışıyor...\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 for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // İptal sinyali wg.Wait() // Tüm goroutine'lerin bitmesini bekle fmt.Println("Ana program sona erdi.") }
Yöntem seçimi, belirli kullanım durumuna ve goroutine etkileşimlerinin karmaşıklığına bağlıdır. Genel olarak, bağlam zincirleme iptal işlemleri için tercih edilir.