2

我目前正在学习 Go 和 ZeroMQ,本着这种精神,我正在尝试为Zguide贡献 Go 示例。我在中断示例上有点挣扎。我不确定处理问题的惯用方式是什么。

我目前拥有的解决方案如下:我创建一个接收 SIGINT 信号的通道。当它发生时,我在主循环中使用的另一个通道上写一个布尔值来中断。问题是,Recv 是阻塞的,循环永远不会检查循环条件。我通过将 NOBLOCK 常量传递给 Recv 来规避这个问题。但我觉得有一种更好的方法,因为 Recv 在中断时应该返回一个 EINTR(据我所知,它并没有)。你们读者比我更有能力回答这个问题,你怎么看?

为了您的方便,我到目前为止的代码:

package main

import (
    "os/signal"
    "os"
    "fmt"
    zmq "github.com/alecthomas/gozmq"
)

func listenForSignals(exit_channel chan bool) {
    signal_channel := make(chan os.Signal)
    signal.Notify(signal_channel)
    <- signal_channel
    fmt.Println("stopping")
    exit_channel <- true
}

func main() {
    exit := make(chan bool)
    exit_signal := false
    go listenForSignals(exit)

    context, _ := zmq.NewContext()
    defer context.Close()

    socket, _ := context.NewSocket(zmq.REP)
    defer socket.Close()
    socket.Bind("tcp://*:5555")

    for exit_signal == false {
      select {
      case exit_signal = <- exit:
        fmt.Println("W: interrupt received, killing server...")
      default:
        msgbytes, err := socket.Recv(zmq.NOBLOCK)
        fmt.Printf("%s.\n", string(msgbytes))
      }
    }

}

编辑根据反馈在一定程度上简化了代码

4

2 回答 2

2

如果您打算使用 select 语句来切换频道,您也应该在频道上返回 socket.Recv 的结果。这也让您可以在 goroutine 上运行 socket.Recv,因此阻塞性质不是问题。

实际上,您可能还应该处理您遇到的错误。您可以通过向整个 shebang 添加另一个频道来做到这一点。

func main() {
    ...

    data := make(chan []byte)
    errors := make(chan error)
    go function() {
      for {
        msgbytes, err := socket.Recv(0)
        if err != nil {
          errors <- err
        } else {
          data <- msgbytes
        }
      }
    }()

    for exit_signal == false {
      select {
      case exit_signal = <- exit:
        fmt.Println("W: interrupt received, killing server...")
      case err := <- errors:
        fmt.Println("Receive Error:", err.Error())
      case msgbytes := <- data:
        fmt.Printf("%s.\n", string(msgbytes))
      }
    }

}
于 2012-07-02T18:45:30.100 回答
0

这看起来有点太复杂了。在 main 中,您可以启动一个等待中断信号的 goroutine:

go func() {
    sigchan := make(chan os.Signal, 10)
    signal.Notify(sigchan, os.Interrupt)
    <-sigchan
    log.Println("Application killed !")
    // do things like writing your last will or cursing the killer before you really die        
    os.Exit(2)
}()
// starts the things your application has to do
于 2012-06-18T10:34:58.003 回答