【问题标题】:Getting value from Go channel从 Go 渠道获取价值
【发布时间】:2013-01-16 19:41:00
【问题描述】:

我有一个监听 TCP 连接的 go-routine,并在通道上将这些连接发送回主循环。我在 go-routine 中执行此操作的原因是使此侦听非阻塞并能够同时处理活动连接。

我已经使用带有空默认情况的 select 语句实现了这一点,如下所示:

go pollTcpConnections(listener, rawConnections)

for {
    // Check for new connections (non-blocking)
    select {
    case tcpConn := <-rawConnections:
        currentCon := NewClientConnection()
        pendingConnections.PushBack(currentCon)
        fmt.Println(currentCon)
        go currentCon.Routine(tcpConn)
    default:
    }
   // ... handle active connections
}

这是我的 pollTcpConnections 例程:

func pollTcpConnections(listener net.Listener, rawConnections chan net.Conn) {
  for {
    conn, err := listener.Accept()  // this blocks, afaik
    if(err != nil) {
        checkError(err)
    }
    fmt.Println("New connection")
    rawConnections<-conn
  }
}

问题是我从来没有收到这些连接。如果我以阻塞方式执行此操作,如下所示:

for {
    tcpConn := <-rawConnections
// ...
}

我收到了连接,但它阻塞了......我也尝试过缓冲通道,但同样的事情发生了。我在这里错过了什么?

【问题讨论】:

标签: select tcp go nonblocking channel


【解决方案1】:

根据现有代码,很难说出您为什么看不到任何连接。您的示例的一个问题是您在 select 语句中有一个空的 default 案例,然后我们看不到这个 for 循环中还发生了什么。按照您编写的方式,该循环可能永远不会屈服于调度程序。您基本上是在说“从频道获取东西。没有?好吧,重新开始。从频道获取东西!”,但您实际上从不等待。当你做一些阻塞你的 goroutine 的操作时,那个 goroutine 让给调度程序。因此,当您以正常方式进行通道读取时,如果没有要读取的值,则该 goroutine 被阻塞读取。由于它被阻塞了,它也让调度器允许其他 goroutines 继续在底层线程上执行。我很确定这就是为什么您的select 带有一个空的default 会中断的原因;您导致该 goroutine 在 for 循环上无限循环,而不会屈服于调度程序。

目前还不清楚pendingConnections的作用是什么,或者根本不需要。

从行为中无法分辨的另一件事是您的 checkError 函数的作用。例如,它不会继续到 for 循环的顶部,或者保释。

无论如何,这看起来比它需要的要复杂。只需有一个将新连接作为参数的函数,然后在连接时在新的 goroutine 中启动它。我总是这样写:

func handleConnection(c net.Conn) {
    // do something with your connection here.
}

for {
    // Wait for a connection.
    conn, err := l.Accept()
    if err != nil {
        // do something with your error.  You probably want to break or return here.
        break
    }
    // handle each connection in a new goroutine
    go handleConnection(conn)
}

这或多或少正是他们在the documentation 中所做的。

【讨论】:

  • 感谢您的回答。汤姆向我指出了另一个有同样问题的问题。添加 runtime.Gosched() “修复”了这个问题,但我知道这可能意味着我的设计很糟糕。你的例子是好的,除了 l.Accept() 块。我想继续在同一个循环中做事。
猜你喜欢
  • 2020-10-02
  • 2021-08-08
  • 2021-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-16
  • 2016-04-15
  • 2015-09-01
相关资源
最近更新 更多