#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()
}