为了账号安全,请及时绑定邮箱和手机立即绑定

从 goroutine 通道读取而不阻塞

从 goroutine 通道读取而不阻塞

Go
ABOUTYOU 2022-10-17 10:14:01
我有两个 goroutines:mainworker和 a helper,它为了一些帮助而分拆出来。 helper可能会遇到错误,所以我使用通道将错误helper从worker.func helper(c chan <- error) (){    //do some work    c <- err // send errors/nil on c}这是如何helper()调用的:func worker() error {    //do some work    c := make(chan error, 1)    go helper(c)    err := <- c    return err}问题:语句是否err := <- c阻塞worker?我不这么认为,因为通道是缓冲的。如果它是阻塞的,我如何使它成为非阻塞的?我的要求是worker让其调用者继续进行其余的工作,而无需等待值出现在通道上。谢谢。
查看完整描述

3 回答

?
MMTTMM

TA贡献1869条经验 获得超4个赞

您可以轻松验证


func helper(c chan<- error) {

    time.Sleep(5 * time.Second)

    c <- errors.New("") // send errors/nil on c

}


func worker() error {

    fmt.Println("do one")


    c := make(chan error, 1)

    go helper(c)


    err := <-c

    fmt.Println("do two")


    return err

}


func main() {

    worker()

}

问:语句 err := <- c 阻塞工作者吗?我不这么认为,因为通道是缓冲的。

- 答: err := <- c会阻止工人。

问:如果是阻塞的,我如何使它成为非阻塞的?我的要求是让 worker 及其调用者继续完成其余的工作,而无需等待值出现在通道上。

A:如果您不想阻止,只需删除err := <-c. 如果你在最后需要错误,只需移动err := <-c到最后。

没有阻塞就无法读取通道,如果没有阻塞就不能再执行此代码,除非您的代码处于循环中。

Loop:

    for {

        select {

        case <-c:

            break Loop

        default:

            //default will go through without blocking

        }

        // do something

    }

你见过errgroup或 waitgroup 吗?

它使用原子、取消上下文和sync.Once 来实现这一点。

https://github.com/golang/sync/blob/master/errgroup/errgroup.go

https://github.com/golang/go/blob/master/src/sync/waitgroup.go

或者你可以直接使用它,运行你的函数,然后在你想要的任何地方等待错误。


查看完整回答
反对 回复 2022-10-17
?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

在您的代码中,其余工作与帮助程序是否遇到错误无关。其余工作完成后,您可以简单地从频道接收。


func worker() error {

    //do some work

    c := make(chan error, 1)

    go helper(c)

    //do rest of the work

    return <-c

}


查看完整回答
反对 回复 2022-10-17
?
拉丁的传说

TA贡献1789条经验 获得超8个赞

我想你需要这个代码..


运行此代码


package main


import (

    "log"

    "sync"

)


func helper(c chan<- error) {


    for {

        var err error = nil

        // do job


        if err != nil {

            c <- err // send errors/nil on c

            break

        }

    }


}


func worker(c chan error) error {

    log.Println("first log")


    go func() {

        helper(c)

    }()


    count := 1

    Loop:

        for {

            select {

            case err := <- c :

                return err

            default:

                log.Println(count, " log")

                count++

                isFinished := false

                // do your job

                if isFinished {

                    break Loop // remove this when you test


                }

            }

        }

    return nil

}


func main() {

    wg := sync.WaitGroup{}

    wg.Add(1)

    go func() {

        c := make(chan error, 1)

        worker(c)

        wg.Done()

    }()

    wg.Wait()

}


查看完整回答
反对 回复 2022-10-17
  • 3 回答
  • 0 关注
  • 130 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信