从Go频道获取价值

时间:2013-02-01 13:21:15

标签: select tcp go nonblocking channel

我有一个go例程,它正在侦听TCP连接并将这些连接发送回主循环。我在go例程中执行此操作的原因是使此侦听无阻塞并且能够同时处理活动连接。

我用一个带有空默认情况的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
// ...
}

我收到了连接,但它阻止了......我也试过缓冲频道,但同样的事情发生了。我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

有点难以说明为什么你没有看到基于现有代码的任何连接。您的示例的一个问题是default语句中有一个空select个案例,然后我们无法看到此for循环中还发生了什么。你编写它的方式,该循环可能永远不会屈服于调度程序。你基本上是在说“从频道中获取一个东西。没有一个?好吧,重新开始。从频道中获取一些东西!”,但你真的没有等待。当您执行一些阻止goroutine的操作时,该goroutine会产生调度程序。因此,当您以正常方式读取通道时,如果没有值可读,则该goroutine被阻止读取。由于它被阻止,它也会产生调度程序以允许其他goroutine继续在底层线程上执行。我很确定这就是为什么你的selectdefault正在破坏;你导致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中所做的完全相同。