从另一个线程中止zeromq recv()或poll() - 立即无需等待超时

时间:2015-06-26 14:51:18

标签: python c++ zeromq

我在许多配置中使用Python和C ++中的ZeroMQ,我想知道哪种方法是从另一个线程中止recv()poll()的最优雅方式(例如,在受控程序的情况下)终止,但如果你想停止听,而不需要杀掉套接字)。

this问题相反,我并不想避免不定期等待,但我想立即从recv()poll()返回

我知道我可以像这样提供timeout和中止recv()

poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)

while _running:
    if poller.poll(timeout=100) == []:
        # maybe handle unwanted timout here..
        continue

    handle_message(socket.recv())

这将无休止地轮询插座,直到_running从另一个线程设置为False - 在完成最多100毫秒之后。

但这并不好 - 我有一个繁忙的循环,这样很难处理真正的超时,这可能是由于不需要的行为造成的。我也必须这样做 等待超时,这在大多数情况下并不重要,但是......你知道我的意思。

当然,我可以轮询一个额外的插座用于堕胎:

abort_socket = context.socket(zmq.SUB)
abort_socket.setsockopt(zmq.SUBSCRIBE, b"")
abort_socket.connect(<abort-publisher-endpoint>)

poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)
poller.register(abort_socket, zmq.POLLIN)

while _running:
    poll_result = poller.poll(timeout=1000)
    if socket in poll_result:
        handle_message(socket.recv())
    elif abort_socket in poll_result:
        break
    else:
        # handle real timeout here
        pass

但这种方法也有缺点:

  • 它有点详细 - 在我触发中止的地方我必须创建一个发布者并使用它来中止接收者
  • abort_socket只能在一个帖子中使用,所以我必须确保

所以我的问题是:这是怎么做到的好方法?

我能以某种方式使用像Python threading.Event或s.th.这样的东西。类似于其他语言,而不是像这样传递给轮询器的abort-socket?:

def listener_thread_fn(event)

    poller = zmq.Poller()
    poller.register(socket, zmq.POLLIN)
    poller.register(event, zmq.POLLIN)

    while _running:
        poll_result = poller.poll(timeout=1000)
        if socket in poll_result:
            handle_message(socket.recv())
        elif event in poll_result:
            break
        else:
            # handle real timeout here
            pass

因此,您必须首先创建theading.Event(),将其传递给listener_thread_fn并从任何线程调用event.set()以中止。

1 个答案:

答案 0 :(得分:1)

使用Python和pyzmq,在recv()poll()中断时会出现错误;所以你可以在发生异常时捕获它。 recv()的示例:

while True:
    try:
        request = server.recv()
    except zmq.ZMQError as e:
        if e.errno == errno.EINTR:
            print('Clean exit now!')
            break
        raise

您可以轻松修改该代码以使用poll()(其程序相同)。另请注意,您需要:

import errno