登录
首页 >  Golang >  Go问答

使用 Golang 的 select 语句与通道和等待组共同工作

来源:stackoverflow

时间:2024-02-26 21:06:29 317浏览 收藏

Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《使用 Golang 的 select 语句与通道和等待组共同工作》带大家来了解一下##content_title##,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力实战开发!


问题内容

通过使用 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
}

解决方案


两个通道都已准备好在 select 语句之前;因此它将通过统一伪随机选择进行选择:

让我们替换代码中的 dosomething 函数调用,并将 defer 放在函数末尾:

package main

import (
    "errors"
    "fmt"
    "sync"
)

func main() {
    errs := make(chan error, 1)
    success := make(chan bool, 1)

    var wg sync.waitgroup
    wg.add(1)
    go func() {
        err := errors.new("some error")
        errs <- err
        wg.done()
    }()

    wg.wait()
    success <- true

    select {
    case err := <-errs:
        fmt.println("error", err)
        panic(err)
    case <-success:
        fmt.println("success")
    }
    fmt.println("finished successfully")
}

正如您在上面的代码示例中看到的,主 goroutine 在 wg.wait() 处等待 wg.done() 此时代码是(几乎)功能上等同于以下代码,并且在此处的 select 语句之前两个通道均已准备就绪

package main

import (
    "errors"
    "fmt"
)

func main() {
    errs := make(chan error, 1)
    success := make(chan bool, 1)
    errs <- errors.new("some error")
    success <- true

    select {
    case err := <-errs:
        fmt.println(err)
    case <-success:
        fmt.println("success")
    }
}

运行:

$ go run .
some error

$ go run .
success

Select_statements

如果一个或多个通信可以继续进行,则通过统一的伪随机选择来选择一个可以继续进行的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句将阻塞,直到至少其中一个通信可以继续。

我认为你应该将 select 放入 go 例程中。像这样:

package main

import (
    "errors"
    "fmt"
    "sync"
)

func main() {
    errs := make(chan error, 1)
    success := make(chan bool, 1)
    go func() {
        select {
        case err := <-errs:
            fmt.Println("error", err)
            panic(err)
        case <-success:
            fmt.Println("success")
        }
        fmt.Println("finished successfully")
    }()

    doSomething(success, errs)
}

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
}

到这里,我们也就讲完了《使用 Golang 的 select 语句与通道和等待组共同工作》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>