Go 由于某种原因,将值传递给通道会阻塞线程

Go 由于某种原因,将值传递给通道会阻塞线程,go,Go,我正在使用通道从HTTP处理程序传递消息: package server import ( "bytes" "errors" "io/ioutil" "log" "net/http" ) type Server struct {} func (s Server) Listen() chan interface{} { ch := make(chan interface{}) http.HandleFunc("/", handle(ch

我正在使用通道从HTTP处理程序传递消息:

package server

import (
    "bytes"
    "errors"
    "io/ioutil"
    "log"
    "net/http"
)

type Server struct {}

func (s Server) Listen() chan interface{} {
    ch := make(chan interface{})
    http.HandleFunc("/", handle(ch))
    go http.ListenAndServe(":8080", nil)
    return ch
}

func handle(ch chan interface{}) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        b, err := ioutil.ReadAll(r.Body)
        defer r.Body.Close()
        if err != nil {
            ch <- errors.New(string(500))
            return
        }
        w.Write([]byte("Hello World"))
        log.Print("about to pass to handler channel")
        ch <- bytes.NewBuffer(b)
        log.Print("passed to handler channel")
    }
} 
但是线程仍然阻塞在同一条线上。为了澄清,我发送请求的方式没有问题。如果我删除上面的通道发送行,线程不会阻塞。

因为通道是,发送操作会阻塞,直到有人准备好从他们那里接收。缓冲通道只会延迟阻塞,因此您总是需要一些读取goroutine

更新到您的更新:程序的控制流如下所示:

  • 服务器开始侦听
  • main
    发送请求并等待响应
  • 服务器收到请求并尝试写入通道
  • main
    从频道读取
  • 4只能在2之后发生,2被3阻止,3被阻止是因为4尚未发生。经典的死锁。

    因为通道是,发送操作会一直阻塞,直到有人准备好接收他们的信息。缓冲通道只会延迟阻塞,因此您总是需要一些读取goroutine

    更新到您的更新:程序的控制流如下所示:

  • 服务器开始侦听
  • main
    发送请求并等待响应
  • 服务器收到请求并尝试写入通道
  • main
    从频道读取

  • 4只能在2之后发生,2被3阻止,3被阻止是因为4尚未发生。经典的死锁。

    我认为@bereal对使用无缓冲或同步通道给出了很好的解释

    另一种方法是通过将创建通道的线更改为:

    ch := make(chan interface{}, 1)   // added the 1
    

    这将防止功能被阻塞。

    我认为@bereal对使用无缓冲或同步通道给出了很好的解释

    另一种方法是通过将创建通道的线更改为:

    ch := make(chan interface{}, 1)   // added the 1
    

    这将防止函数被阻塞。

    我在代码中添加了缺失的部分并运行了它,一切正常。我看不到任何街区。代码如下:

    package main
    
    import (
        "bytes"
        "errors"
        "io/ioutil"
        "log"
        "net/http"
        "time"
    )
    
    type Server struct{}
    
    func (s *Server) Listen() chan interface{} {
        ch := make(chan interface{})
        http.HandleFunc("/", handle(ch))
        go http.ListenAndServe(":8080", nil)
        return ch
    }
    
    func handle(ch chan interface{}) func(http.ResponseWriter, *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            b, err := ioutil.ReadAll(r.Body)
            defer r.Body.Close()
            if err != nil {
                ch <- errors.New(string(500))
                return
            }
            w.Write([]byte("Hello World"))
            log.Print("about to pass to handler channel")
            ch <- bytes.NewBuffer(b)
            log.Print("passed to handler channel")
        }
    }
    
    // SendRequest send request
    func SendRequest(method string, url string, data []byte) {
        tr := &http.Transport{
            MaxIdleConns:       10,
            IdleConnTimeout:    30 * time.Second,
            DisableCompression: true,
        }
        client := &http.Client{Transport: tr}
        reader := bytes.NewReader(data)
        req, err := http.NewRequest(method, url, reader)
        if err != nil {
            panic(err)
        }
        client.Do(req)
    }
    
    func main() {
        n := new(Server)
        listenerChan := n.Listen()
        go SendRequest("POST", "http://localhost:8080", []byte("hello"))
        for listenedMsg := range listenerChan {
            log.Print("listened message>>>> ", listenedMsg)
        }
    }
    

    我在您的代码中添加了缺失的部分并运行了它,一切正常。我看不到任何街区。代码如下:

    package main
    
    import (
        "bytes"
        "errors"
        "io/ioutil"
        "log"
        "net/http"
        "time"
    )
    
    type Server struct{}
    
    func (s *Server) Listen() chan interface{} {
        ch := make(chan interface{})
        http.HandleFunc("/", handle(ch))
        go http.ListenAndServe(":8080", nil)
        return ch
    }
    
    func handle(ch chan interface{}) func(http.ResponseWriter, *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            b, err := ioutil.ReadAll(r.Body)
            defer r.Body.Close()
            if err != nil {
                ch <- errors.New(string(500))
                return
            }
            w.Write([]byte("Hello World"))
            log.Print("about to pass to handler channel")
            ch <- bytes.NewBuffer(b)
            log.Print("passed to handler channel")
        }
    }
    
    // SendRequest send request
    func SendRequest(method string, url string, data []byte) {
        tr := &http.Transport{
            MaxIdleConns:       10,
            IdleConnTimeout:    30 * time.Second,
            DisableCompression: true,
        }
        client := &http.Client{Transport: tr}
        reader := bytes.NewReader(data)
        req, err := http.NewRequest(method, url, reader)
        if err != nil {
            panic(err)
        }
        client.Do(req)
    }
    
    func main() {
        n := new(Server)
        listenerChan := n.Listen()
        go SendRequest("POST", "http://localhost:8080", []byte("hello"))
        for listenedMsg := range listenerChan {
            log.Print("listened message>>>> ", listenedMsg)
        }
    }
    

    @沃尔克一个人可以不受这种咆哮的影响。如果您不能提供帮助,请不要回答。@dopatraman-运行您的示例,减去
    SendRequest
    函数-我可以在不发送到频道的情况下运行此示例blocking@Volker一个人可以不受这种咆哮的影响。如果您不能提供帮助,请不要回答。@dopatraman-运行您的示例,减去
    SendRequest
    函数-我能够在没有发送到通道阻塞的情况下运行此示例,我正在从主线程上的通道读取。请查看更新的问题:@dopatraman您在开始从频道读取之前发送了请求,请求已被写入阻止。感谢您提供的信息。但我必须不好意思地承认,我仍然无法让它发挥作用。你介意发布一些伪代码吗?你会如何改变我现在正在做的事情?我正在读主线程上的频道。请查看更新的问题:@dopatraman您在开始从频道读取之前发送了请求,请求已被写入阻止。感谢您提供的信息。但我必须不好意思地承认,我仍然无法让它发挥作用。你介意发布一些伪代码吗?你会如何改变我现在所做的?
    2018/06/28 17:22:10 about to pass to handler channel
    2018/06/28 17:22:10 passed to handler channel
    2018/06/28 17:22:10 listened message>>>> hello