如何正确关闭aiozmq / zmq?

时间:2017-08-21 21:21:57

标签: python python-3.x python-asyncio pyzmq

当我的后端没有运行时,我遇到了这个问题 你可以在这里找到一个非常简单的演示来重现我的情况(如果你想节省一些时间,可以将超时减少到1):

#!/usr/bin/env python3

import threading
import logging
import asyncio
from aiozmq import rpc

logging.getLogger().setLevel(logging.DEBUG)

async def go():
    logging.debug('Go !')
    client = None
    try:
        client = await rpc.connect_rpc(connect='tcp://127.0.0.1:5555', timeout=5)
        await client.call.remote(1, 2)
    except Exception as e:
        logging.exception(e)
    finally:
        if client is not None:
            client.close()
            await client.wait_closed()

    logging.debug('done')

loop = asyncio.get_event_loop()
loop.run_until_complete(go())
loop.close()

logging.debug(asyncio.Task.all_tasks())
logging.debug(threading.enumerate())

您会注意到coro(go&我们wait_for)已完成,而python只跟踪MainThread
但是您可以在顶部(htop)看到您的脚本实际上有2个线程正在运行。

  • 1在epoll_wait(10,
  • 上被屏蔽了
  • 循环播放:

    epoll_wait(13, [], 256, 168)            = 0
    socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
    fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
    fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
    fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
    connect(3, {sa_family=AF_INET, sin_port=htons(5555), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
    epoll_ctl(13, EPOLL_CTL_ADD, 3, {0, {u32=1275071824, u64=140476770422096}}) = 0
    epoll_ctl(13, EPOLL_CTL_MOD, 3, {EPOLLOUT, {u32=1275071824, u64=140476770422096}}) = 0
    epoll_wait(13, [{EPOLLOUT|EPOLLERR|EPOLLHUP, {u32=1275071824, u64=140476770422096}}], 256, -1) = 1
    epoll_ctl(13, EPOLL_CTL_DEL, 3, 0x7fc34c000d54) = 0
    getsockopt(3, SOL_SOCKET, SO_ERROR, [111], [4]) = 0
    close(3)                                = 0
    

我不是百分百肯定,但我认为我们收到的EPOLLOUT|EPOLLERR|EPOLLHUP是HUP = HangUp = ConnectionRefused。

我将剩余/不可见的线程跟踪到zmq库中的某个位置。

有人知道发生了什么以及如何正确阻止它吗?

1 个答案:

答案 0 :(得分:0)

我还在github上发布了这个issue并得到了答案。

这实际上是由于Linger period

解决方案只是在调用client.transport.setsockopt(zmq.LINGER, 0)之后立即添加connect_rpc

loop.is_running()关闭的if中添加finally可能也很有用,以防止在循环不再运行时关闭套接字的任何尝试(由于另一个异常)例如)。