在对Golang进行实验时,我创建了一个带有select语句的函数,该函数监听两个通道。
我的问题是代码似乎表现得不确定-有时它会恐慌,有时它会成功完成。
**我的期望是这段代码应该总是会死机。**它应该首先接收到错误,因为它应该在waitGroup完成之前被调度,因此在成功通道被推送到之前。
package main
import (
"errors"
"fmt"
"sync"
)
func main() {
errs := make(chan error, 1)
success := make(chan bool, 1)
doSomething(success, errs)
select {
case err := <-errs:
fmt.Println("error", err)
panic(err)
case <-success:
fmt.Println("success")
}
fmt.Println("finished successfully")
}
func doSomething(success chan bool, errs chan error) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := errors.New("Some error")
errs <- err
}()
wg.Wait()
success <- true
}
2条答案
按热度按时间oogrdqng1#
两个通道在select语句前都已就绪;所以它将通过均匀伪随机选择来选择:
让我们替换代码中的
doSomething
函数调用,并将defer放在函数的末尾:正如你在上面的代码示例中看到的,主goroutine在
wg.Wait()
等待wg.Done()
在这个时间点代码(几乎)在功能上等于下面的代码,并且两个通道都准备好了在这里的select语句之前:运行:
Select语句(_S):
如果一个或多个通信可以继续进行,则通过均匀伪随机选择**选择可以继续进行的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“select”语句阻塞,直到至少一个通信可以继续。
uqcuzwp82#
我认为你应该把select放到一个go例程中。像这样: