猿问

带有通道和等待组的 Golang 选择语句

在使用 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

}


开满天机
浏览 82回答 1
1回答

互换的青春

在 select 语句之前,两个通道都准备好了;因此它将通过统一的伪随机选择进行选择:让我们替换doSomething代码中的函数调用,并将 defer 放在函数的末尾:package mainimport (&nbsp; &nbsp; "errors"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync")func main() {&nbsp; &nbsp; errs := make(chan error, 1)&nbsp; &nbsp; success := make(chan bool, 1)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; err := errors.New("some error")&nbsp; &nbsp; &nbsp; &nbsp; errs <- err&nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; }()&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; success <- true&nbsp; &nbsp; select {&nbsp; &nbsp; case err := <-errs:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error", err)&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; case <-success:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("success")&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("finished successfully")}正如你在上面的代码示例中看到的,主 goroutine在这个时间点wg.Wait()等待,代码(几乎)在功能上等于以下代码,并且两个通道在此处的 select 语句之前准备好: wg.Done()package mainimport (&nbsp; &nbsp; "errors"&nbsp; &nbsp; "fmt")func main() {&nbsp; &nbsp; errs := make(chan error, 1)&nbsp; &nbsp; success := make(chan bool, 1)&nbsp; &nbsp; errs <- errors.New("some error")&nbsp; &nbsp; success <- true&nbsp; &nbsp; select {&nbsp; &nbsp; case err := <-errs:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; case <-success:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("success")&nbsp; &nbsp; }}跑:$ go run .some error$ go run .success选择语句:如果一个或多个通信可以进行,则通过统一的伪随机选择选择一个可以进行的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。
随时随地看视频慕课网APP

相关分类

Go
我要回答