goruntine не выполняется одновременно?

#go #goroutine

#Вперед #goroutine

Вопрос:

У меня есть следующая программа, я новичок в gorountine, то, что я хочу протестировать, просто, я вызываю gorountine в цикле 100 раз, происходит однократный сбой, вся программа завершается сбоем, в противном случае выполняется успешно, и fail10Percent она задерживается на 1 секунду, и проверьте случайное число, если оно равно 4, дайте ему завершиться сбоем.

 package main

import (
    "fmt"
    "math/rand"
    "time"
)

func fail10Percent(ch chan int) {
    time.Sleep(1 * time.Second)
    e := rand.Intn(10)
    fmt.Println("Calculating rand.Intn(10) ", e)

    if e == 4 {
        ch <- 0
        return
    }
    ch <- 1
}

func test() {
    for i := 0; i < 100; i   {
        err := make(chan int)
        go fail10Percent(err)

        res := <-err

        fmt.Println("=== result: ", res)

        if res != 1 {
            fmt.Println("failed")
            return
        }
    }
    fmt.Println("succeeded")
}

func main() {
    test()
}
  

Я ожидаю, что go fail10Percent(err) будет выполняться одновременно 100 раз, что будет иметь задержку всего в 1 секунду, однако, когда я запускаю его, я вижу, что следующий результат печатается через 1 секунду после 1 секунды, почему это так, и как я могу настроить свою программу, чтобы делать то, что я хочу.

 Calculating rand.Intn(10)  1
=== result:  1
Calculating rand.Intn(10)  7
=== result:  1
Calculating rand.Intn(10)  7
=== result:  1
Calculating rand.Intn(10)  9
=== result:  1
Calculating rand.Intn(10)  1
=== result:  1
Calculating rand.Intn(10)  8
=== result:  1
Calculating rand.Intn(10)  5
=== result:  1
Calculating rand.Intn(10)  0
=== result:  1
Calculating rand.Intn(10)  6
=== result:  1
Calculating rand.Intn(10)  0
=== result:  1
Calculating rand.Intn(10)  4
=== result:  0
failed
  

Комментарии:

1. Потому что вы используете небуферизованный канал, поэтому main просто ждет, пока он не получит что-то на канале. Я рекомендую вам ознакомиться с go, в нем рассказывается об этом и других основах Go.

2. При сбое подпрограммы происходит сбой всей программы, потому что при проверке res != 1 вы возвращаетесь из тестовой функции, что приводит к завершению основной подпрограммы, и, следовательно, программа завершается.

Ответ №1:

Я прокомментировал код для вас, чтобы вы могли понять.

 package main

import (
    "fmt"
    "math/rand"
    "sync"
)

func fail10Percent(ch chan int, w *sync.WaitGroup) {
    defer w.Done()
    num := rand.Intn(10)
    fmt.Println("calculating rand.Intn(10) ", num)
    if num == 4 {
        ch <- 0 // Fail
        return
    }
    ch <- 1 // Pass
}

func test() {
    var ch = make(chan int, 1)
    // Launch the receiver goroutine to listen if goroutine succeeded or failed based on the value sent to ch
    go func() {
        for recv := range ch {
            switch recv {
            // Fail
            case 0:
                fmt.Println("goroutine failed")
            // Pass
            case 1:
                fmt.Println("goroutine succeed")
            }
        }
    }()
    // wg is a WaitGroup
    var wg sync.WaitGroup
    for i := 0; i < 100; i   {
        wg.Add(1)
        go fail10Percent(ch, amp;wg)
    }
    // wg.Wait() to wait for all goroutines to complete
    wg.Wait()
    // Close the channel so that the receiver can stop
    close(ch)
}

func main() {
    test()
}
  

Обновить:

Простое решение без использования sync.WaitGroup

 package main

import (
    "fmt"
    "math/rand"
)

// Using a send only channel
func fail10Percent(ch chan<- int) {
    num := rand.Intn(10)
    fmt.Println("calculating rand.Intn(10) ", num)
    if num == 4 {
        ch <- 0 // Fail
        return
    }
    ch <- 1 // Pass
}

func test() {
    var ch = make(chan int, 1)
    for i := 0; i < 100; i   {
        go fail10Percent(ch)
    }
    for i := 0; i < 100; i   {
        if recv := <-ch; recv == 0 {
            fmt.Println("goroutine failed")
        } else if recv == 1 {
            fmt.Println("goroutine succeed")
        }
    }
    close(ch)
}

func main() {
    test()
}