2013-06-18 7 views
4

Следуя примеру this в документах ØMQ, я пытаюсь создать простой приемник. В этом примере используется бесконечный цикл. Все работает отлично. Однако в MS Windows, когда я нажимаю CTRL + C, чтобы поднять KeyboardInterrupt, цикл не прерывается. Кажется, что метод recv() каким-то образом игнорирует исключение. Тем не менее, мне бы хотелось выйти из процесса, нажимая CTRL + C, а не убивая его. Это возможно?Остановить приемник pyzmq KeyboardInterrupt

ответ

2

zmq.Poller объект кажется, чтобы помочь:

def poll_socket(socket, timetick = 100): 
    poller = zmq.Poller() 
    poller.register(socket, zmq.POLLIN) 
    # wait up to 100msec 
    try: 
     while True: 
      obj = dict(poller.poll(timetick)) 
      if socket in obj and obj[socket] == zmq.POLLIN: 
       yield socket.recv() 
    except KeyboardInterrupt: 
     pass 
    # Escape while loop if there's a keyboard interrupt. 

Затем вы можете сделать такие как:

for message in poll_socket(socket): 
    handle_message(message) 

, а цикл for-loop будет автоматически завершен на Ctrl-C. Похоже, что перевод с Ctrl-C на Python KeyboardInterrupt происходит только тогда, когда интерпретатор активен, и Python не дал управление низкоуровневому C-коду; вызов pyzmq recv(), по-видимому, блокируется при низкоуровневом C-коде, поэтому Python никогда не получит возможность выпускать KeyboardInterrupt. Но если вы используете zmq.Poller, то он остановится с таймаутом и даст интерпретатору шанс выпустить KeyboardInterrupt после завершения таймаута.

+2

На сегодняшний день я по-прежнему вынужден убивать свои приложения вместо того, чтобы нажимать CTRL + C - очень неудобно ... Я также работаю с 'zmq.Poller' (спасибо за шаблон« for..in » , btw.!), но есть ситуации, когда Poller не помогает: 1) использование встроенных устройств ('zmq.device()'), 2) использование сокетов REQ в случае разрыва REP-работника. Я обнаружил следующее: http://zguide.zeromq.org/py:interrupt, но не нашел его в использовании. – Tregoreg

2

Не знаю, если это будет работать в Windows, но в Linux я сделал что-то вроде этого:

if signal.signal(signal.SIGINT, signal.SIG_DFL): 
    sys.exit() 
+1

Это не работает для меня точно, '' sys.exit() '' всегда называется - в docs, я обнаружил, что '' signal.signal (...) '' только устанавливает обработчик сигнала. Однако, ставя '' signal.signal (signal.SIGINT, signal.SIG_DFL); '' перед бесконечным циклом решает мою проблему, и теперь можно завершить приемник с помощью CTRL + C! Так что спасибо за подсказку! – Tregoreg

+0

@Tregoreg, вы должны выслать свой комментарий в качестве ответа. Я подниму его ... работал для меня и намного чище, чем менял, как мой код обрабатывает обработку запросов. – Cyclone

+0

@Cyclone Спасибо за отзыв, я сделал, как вы и предложили. – Tregoreg

1

Попробуйте ctrl + break (как в ключе выше страницы Up, мне нужно было посмотреть его, я не думаю, что я когда-либо касался этого ключа раньше) предложил в нижней части this thread. Я не делал ничего необычного, но, похоже, это хорошо работает в тех случаях, которые я пробовал.

4

В ответ на просьбу @ Циклон, я предлагаю следующее в качестве возможного решения:

import signal 

signal.signal(signal.SIGINT, signal.SIG_DFL); 
# any pyzmq-related code, such as `reply = socket.recv()` 
+2

Это работает на удивление хорошо, но как? – skrat