Идиоматический способ обработки прерываний в Go с использованием ZeroMQ

В настоящее время я изучаю Go и ZeroMQ, и в этом духе я пытаюсь предоставить примеры Go для Zguide. У меня возникли трудности с примером прерывания. Я не уверен, каким будет идиоматический способ решения проблемы.

В настоящее время у меня есть следующее решение: я создаю канал, который получает сигнал 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))
      }
    }

}

Изменить несколько упростил код на основе отзывов


person harm    schedule 18.06.2012    source источник
comment
это, вероятно, не очень хорошая идея, поскольку вы проверяете сокет в цикле без периода задержки восстановления. Интересно, каково было бы использование процессора этой программой.   -  person Sridhar Ratnakumar    schedule 19.10.2012


Ответы (2)


Если вы собираетесь использовать оператор select для переключения каналов, вы также должны вернуть результат socket.Recv для канала. Это также позволяет вам запускать socket.Recv в горутине, поэтому блокирующий характер не является проблемой.

На самом деле вам, вероятно, также следует обрабатывать ошибки, которые вы получаете. Это вы можете сделать, добавив еще один канал ко всему шебангу.

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))
      }
    }

}
person Matt Balkam    schedule 02.07.2012

Это выглядит слишком сложным. В основном вы можете запустить горутину, ожидающую сигнала прерывания:

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
person Denys Séguret    schedule 18.06.2012
comment
os.Exit(0) закроет всю программу, верно? Не только горутина. - person harm; 18.06.2012
comment
Да, но это то, что нужно делать, когда вы получаете прерывание. Кстати, вы не выходите из горутины, она просто заканчивается по завершении. - person Denys Séguret; 18.06.2012
comment
вызов os.Exit(0) по прерыванию не очень продуман. - person alphazero; 18.06.2012
comment
Можете ли вы объяснить, почему? Обратите внимание, что в моем реальном коде я останавливаюсь операции записи перед выполнением этой строки. Как вы организуете завершение вашего приложения? - person Denys Séguret; 18.06.2012
comment
@cormacrelf Спасибо за объяснение. - person Denys Séguret; 15.01.2014