Sobes.tech
Middle

როგორ სწორად დაასრულოთ რამდენიმე goroutine-ის შესრულება Go-ში?

sobes.tech AI

პასუხი AI-სგან

არსებობს რამდენიმე გავრცელებული მეთოდი:

  • კონტექსტის გამოყენება (Context): რეკომენდებული მიდგომაა ოპერაციების გაუქმებისთვის ხის სტრუქტურაში. კონტექსტი შეიძლება გადასცეს გაუქმების სიგნალი არხის მეშვეობით.

    package main
    
    import (
        "context"
        "fmt"
        "time"
    )
    
    func worker(ctx context.Context, id int) {
        for {
            select {
            case <-ctx.Done():
                fmt.Printf("გორუტინა %d დასრულდება: %v\n", id, ctx.Err())
                return
            default:
                fmt.Printf("გორუტინა %d მუშაობს...\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 * დროის სექუნდი)
        cancel() // გაუქმების სიგნალის გაგზავნა
    
        time.Sleep(1 * დროის სექუნდი) // გორუტინების დასრულების დროის მიცემა
        fmt.Println("ძირითადი პროგრამა დასრულდა.")
    }
    
  • არხების გამოყენება: გაუქმების სიგნალის გასაგზავნად (მაგალითად, ცარიელი სტრუქტურა struct{}) სპეციალურ არხზე, შეგვიძლია გორუტინს ვუთხრათ, რომ უნდა დასრულდეს.

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func worker(stopChan <-chan struct{}, id int) {
        for {
            select {
            case <-stopChan:
                fmt.Printf("გორუტინა %d დასრულდება არხით\n", id)
                return
            default:
                fmt.Printf("გორუტინა %d მუშაობს...\n", id)
                time.Sleep(1 * დროის სექუნდი)
            }
        }
    }
    
    func main() {
        stopChan := make(chan struct{})
    
        go worker(stopChan, 1)
        go worker(stopChan, 2)
    
        time.Sleep(3 * დროის სექუნდი)
        close(stopChan) // არხის დახურვა სიგნალს აძლევს დასრულების შესახებ
    
        time.Sleep(1 * დროის სექუნდი) // გორუტინების დასრულების დროის მიცემა
        fmt.Println("ძირითადი პროგრამა დასრულდა.")
    }
    
  • sync.WaitGroup-ის გამოყენება (დასრულების მოსალოდნელობისთვის, არა სიგნალისთვის): WaitGroup გამოიყენება გორუტინების დასრულების მოსალოდნელობისთვის, მაგრამ თავად არ უზრუნველყოფს გაჩერების მექანიზმს. ხშირად გამოიყენება კონტექსტთან ან არხებთან ერთად.

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    
    func worker(ctx context.Context, wg *sync.WaitGroup, id int) {
        defer wg.Done() // ვამცირებთ WaitGroup-ის გამოთვლას გორუტინის დასრულებისას
    
        for {
            select {
            case <-ctx.Done():
                fmt.Printf("გორუტინა %d დასრულდება\n", id)
                return
            default:
                fmt.Printf("გორუტინა %d მუშაობს...\n", id)
                time.Sleep(1 * დროის სექუნდი)
            }
        }
    }
    
    func main() {
        ctx, cancel := context.WithCancel(context.Background())
        var wg sync.WaitGroup
    
        numWorkers := 2
        wg.Add(numWorkers) // ვაწყობთ WaitGroup-ს
    
        for i := 1; i <= numWorkers; i++ {
            go worker(ctx, &wg, i)
        }
    
        time.Sleep(3 * დროის სექუნდი)
        cancel() // გაუქმების სიგნალი
    
        wg.Wait() // ველით ყველა გორუტინის დასრულებას
        fmt.Println("ძირითადი პროგრამა დასრულდა.")
    }
    

შერჩევა მეთოდის დამოკიდებულია კონკრეტულ შემთხვევაზე და გორუტინების ურთიერთქმედების სირთულეზე. კონტექსტი ჩვეულებრივ სასურველია კასკადური გაუქმებისთვის.