繁体   English   中英

为什么这个 goroutine 在通道上收不到发送的值

[英]Why does this goroutine not receive the sent value on the channel

我在通道上发送 http 请求并返回一个通道以读取每个请求:

func reqs(done <-chan bool, reqs ...*http.Request) chan *http.Request {
        out := make(chan *http.Request)

        go func() {

                defer close(out)
                for _, r := range reqs {
                        select {
                        case out <- r:
                        case <-done:
                                return
                        }

                }
        }()

        return out
}
  1. 我有一种方法可以从频道中读取请求。
func (a *ReadReq) req1(done chan bool, ch chan *http.Request) chan []byte {
        out := make(chan []byte)

        go func(ch chan *http.Request) {

                defer close(out)
                r, ok := <-ch
                
                if !ok{
                panic("no value received on channel for req1")
                } 

                rb, err := ioutil.ReadAll(r.Body)

                if err != nil {
                        panic(err)
                }

                errj := json.Unmarshal(rb, a)

                if errj != nil {
                        panic(errj)
                }

                rbody := a.withdrawRequest().inAmount()
                bb, errbb := json.Marshal(rbody)

                if errbb != nil {
                        panic(errbb)
                }

                select {
                case out <- bb:
                case <-done:
                        return
                }
        }(ch)

        return out
}
  1. 当我调用 function a.req1(done, ch)时,通道上没有收到请求
func (a *ReadReq) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        done := make(chan bool)
        defer close(done)

        ch := reqs(done, r)

        for request := range ch {
                err := request.ParseForm()
                if err != nil{
                panic(err)
                }

                switch param := request.Form.Get("reqx"); param {
                case "001":
                        chreq1 := a.req1(done, ch)
                        w.Write(<-chreq1)
                        return

                case "002":
                        chreq2 := a.req2(done, ch)
                        w.Write(<-chreq2)
                        return
                }
        }

}

在这个实现中我哪里出错了。

我已将您的代码简化为 3 个函数,并在评论中解释了原因:

package main

import "fmt"

// pass parameters into channel and handle them orderly
// f1 will work properly
func f1(doneCh chan bool, args ...int) chan int {
    argCh := make(chan int)
    go func() {
        defer close(argCh) // cause
        for _, arg := range args {
            select {
            case argCh <- arg:
            case <-doneCh:
                return
            }
        }
        fmt.Println("f1: exit loop goroutine, close the argCh")
    }()
    return argCh
}

func f2(n int) {
    doneCh := make(chan bool)
    defer close(doneCh)

    argCh := f1(doneCh, n)
    for arg := range argCh {
        // 1. we taken the ONLY ONE arg from argCh, just like you taken request object from out channel
        fmt.Printf("f2: taken %d from argCh\n", arg)

        // 2. now f1 goroutine exiting the loop, and argCh channel will be defer closed

        // here is the problem
        // 3. you passed the CLOSED channel argCh info f3
        outCh := f3(doneCh, argCh)
        fmt.Println("f3 result:", <-outCh)
    }
}

func f3(doneCh chan bool, inCh chan int) chan int {
    outCh := make(chan int)
    go func(ch chan int) {
        defer close(outCh)
        n, ok := <-ch
        fmt.Printf("f3: n: %d, ok: %t\n", n, ok)
        // want 10, true
        // got  0, false
        // since ch has been closed, the false is expected, 0 is default value of channel type which shouldn't be used
        select {
        case outCh <- n + 1:
        case <-doneCh:
            return
        }
    }(inCh)
    return outCh
}

func main() {
    f2(999)
}

output:

f1: exit loop goroutine, close the argCh
f2: taken 999 from argCh
f3: n: 0, ok: false
f3 result: 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM