Sobes.tech
Middle

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.WaitGroup kullanı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.