登录
首页 >  Golang >  Go问答

go 例程和通道发送响应

来源:stackoverflow

时间:2024-03-07 08:55:25 479浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《go 例程和通道发送响应》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~

问题内容

我有以下代码: 我有一个列表要浏览并使用该列表中的值执行某些操作,因此我想到使用 go 例程,但我需要使用最大数量的 go 例程,然后在 go 例程中我需要进行调用会得到响应的返回,err,当err不同于null时,我需要终止所有go例程并返回http响应,如果没有err我需要终止go例程并返回http响应,

当我有很少的值时,它工作正常,但是当我有很多值时,我有一个问题,因为当我调用取消时,我仍然会有 go 例程尝试发送到已经关闭的响应通道,并且我不断收到错误:

goroutine 36 [chan发送]:

type response struct {
    value string
}

func Testing() []response {

    fakeValues := getFakeValues()

    maxParallel := 25
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    if len(fakeValues) < maxParallel {
        maxParallel = len(fakeValues)
    }

    type responseChannel struct {
        Response response
        Err      error
    }

    reqChan := make(chan string) //make this an unbuffered channel
    resChan := make(chan responseChannel)

    wg := &sync.WaitGroup{}
    wg.Add(maxParallel)
    for i := 0; i < maxParallel; i++ {
        go func(ctx context.Context, ch chan string, resChan chan responseChannel) {
            for {
                select {
                case val := <-ch:
                    resp, err := getFakeResult(val)
                    resChan <- responseChannel{
                        Response: resp,
                        Err:      err,
                    }

                case <-ctx.Done():
                    wg.Done()
                    return
                }
            }
        }(ctx, reqChan, resChan)
    }

    go func() {
        for _, body := range fakeValues {
            reqChan <- body
        }

        close(reqChan)
        cancel()

    }()

    go func() {
        wg.Wait()
        close(resChan)
    }()

    var hasErr error
    response := make([]response, 0, len(fakeValues))
    for res := range resChan {
        if res.Err != nil {
            hasErr = res.Err
            cancel()
            break
        }

        response = append(response, res.Response)
    }

    if hasErr != nil {
        // return responses.ErrorResponse(hasErr) // returns http response
    }

    //  return responses.Accepted(response, nil) // returns http response
    return nil
}

func getFakeValues() []string {
    return []string{"a"}
}

func getFakeResult(val string) (response, error) {
    if val == "" {
        return response{}, fmt.Errorf("ooh noh:%s", val)
    }

    return response{
        value: val,
    }, nil
}

正确答案


工作人员最终在发送到 reschan 时被阻止,因为它没有缓冲,并且在发生错误后,不会从中读取任何内容。 您可以将 reschan 设为缓冲,其大小至少与 maxparallel 一样大。或者检查上下文是否被取消,例如将 reschan <- 更改为

select {
case resChan <- responseChannel{
                    Response: resp,
                    Err:      err,
}:
case <-ctx.Done():
}

到这里,我们也就讲完了《go 例程和通道发送响应》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

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