订户接收消息缓慢

时间:2019-09-26 09:34:04

标签: python python-asyncio python-multithreading pyzmq

我有一个pyzmq Publisher,它每秒发送大约1000条消息。我试图在异步event_loop中启动大约10个订户。

它可以工作,但比唯一一个订阅者的速度慢约2.5倍。

代码可能有什么问题?

import asyncio
import zmq
import json
from zmq.backend.cython.constants import NOBLOCK
from zmq.asyncio import Context, Poller
from loop_ import Loop


class Client:
    REQUEST_TIMEOUT = 35000
    SERVER_ENDPOINT = "tcp://localhost:6666"

    def __init__(self, id_):
        self.id = id_

    def get_task(self):
        return asyncio.create_task(self.client_coroutine())

    async def client_coroutine(self):
        context = Context.instance()

        socket = context.socket(zmq.SUB)
        socket.connect(self.SERVER_ENDPOINT)
        socket.setsockopt(zmq.SUBSCRIBE, b'4')
        poller = Poller()
        poller.register(socket, zmq.POLLIN)

        while True:
            event = dict(await poller.poll(self.REQUEST_TIMEOUT))
            if event.get(socket) == zmq.POLLIN:
                reply = await socket.recv_multipart(flags=NOBLOCK)
                if not reply:
                    break
                else:
                    print(eval(json.loads(reply[1].decode('utf-8'))))
            else:
                print("No response from server, retrying...")
                socket.setsockopt(zmq.LINGER, 0)
                socket.close()
                poller.unregister(socket)

async def tasks():
    _tasks = [Client(id_).get_task() for id_ in range(10)]
    done, pending = await asyncio.wait(_tasks, return_when=asyncio.FIRST_EXCEPTION)


loop = asyncio.get_event_loop()
loop.run_until_complete(tasks())

1 个答案:

答案 0 :(得分:1)

  

Q 代码可能有什么问题?

鉴于代码使用的是相同的 localhost (从使用地址可以看到),可疑的第一位是,要处理的工作量增加了10倍,此类工作量将始终强调localhost的操作系统和CPU,不是吗?

接下来是运输级别的选择。鉴于所有 SUB -和 localhost 共同位于同一 PUB ,所有基于L3堆栈的TCP / IP协议工作都浪费了。要比较相对成本(为此硬件单一消息传递使用 tcp:// 传输类的附加效果),请使用 {{1} } 传输类,其中不会进行与协议相关的TCP / IP堆栈附加处理。

最后但并非最不重要的一点是,我的代码将永远不会混合使用不同的事件循环(自v2.11起使用ZeroMQ,因此有人可能会认为我有点过时了,避免依赖于inproc://装饰的功能最近py3.6 +)

我的代码将像 async 中那样,对每个aSocketINSTANCE使用显式,非阻塞,零等待测试,以检查是否存在消息,而不是使用任何“外部”添加了修饰,可能会报告相同的修饰,但是通过一些附加的操作(昂贵且在我的控制代码范围之外)进行事件处理。所有实时,低延迟的用例都力图承担尽可能小的延迟/开销,因此,在任何“现代”语法糖化技巧下,使用显式控制始终会在我的项目中胜出。

无论如何,享受零的禅宗