Sobes.tech
Middle

Goда бир нече goroutine-дун ишин туура бүтүрүү жолдору?

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 * time.Second)
        cancel() // Жокко чыгаруу сигналын жөнөтүү
    
        time.Sleep(1 * time.Second) // Горутинадардын аяктоо үчүн убакыт берүү
        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 * time.Second)
            }
        }
    }
    
    func main() {
        stopChan := make(chan struct{})
    
        go worker(stopChan, 1)
        go worker(stopChan, 2)
    
        time.Sleep(3 * time.Second)
        close(stopChan) // Каналды жабуу аяктоо белгиленет
    
        time.Sleep(1 * time.Second) // Горутинадардын аяктоо үчүн убакыт берүү
        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 * time.Second)
            }
        }
    }
    
    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 * time.Second)
        cancel() // Жокко чыгаруу сигналы
    
        wg.Wait() // Бардык горутиндардын аяктоосун күтүү
        fmt.Println("Негизги программа аяктады.")
    }
    

Тандоо конкреттүү колдонуу жагдайына жана горутиндардын өз ара аракеттешүүсүнүн татаалдыгына көз каранды. Контекст көбүнчө каскаддык жокко чыгаруу үчүн артыкчылык берилет.