【问题标题】:ZeroMQ: How to construct simple asynchronous broker? Seems impossibleZeroMQ:如何构造简单的异步代理?似乎不可能
【发布时间】:2021-03-25 17:28:31
【问题描述】:

我正在构建一个简单的星型客户端-服务器拓扑。

这个想法是客户端连接到服务器,可以发送消息,并且服务器可以向它们发送消息,当服务器决定时。客户端的数量会相对较少,大约 30 个,但数量太多以至于将所有传出数据发送给所有人是不明智的。我敢肯定我只是头脑简单,但这对于 ZeroMQ 来说似乎是完全不可能的。

最后一部分是this question没有提供答案的原因。

问题是这样的:

我可以使用ROUTER 套接字来接收来自客户端的消息。这也带有身份证明。但是,我不能使用同一个套接字进行发送,因为 ZeroMQ 套接字不是线程安全的。 IE。我不能让一个线程等待传入消息,而另一个线程则从服务器本身发送传出消息。我不知道我可以以任何方式等待阻塞 - socket.recv(),例如队列上的 .get() - 同时在 python 中的单个线程上。也许有办法做到这一点。

使用两个套接字 - 一个传入一个传出 - 也不起作用。标识不会在套接字之间共享,因此即使只有一次,仍必须轮询发送套接字以获取客户端 ID 映射。我们显然不能为每个客户端使用自己的端口。服务器似乎无法出于自己的意愿向单个客户端发送消息。

(订阅主题也是一个死主意:消息过滤是在客户端执行的,服务器只会淹没所有客户端网络)

最终,TCP 套接字可以轻松处理这种异步情况,但是在 python 上构建有效的消息框架是一场噩梦。我所追求的只是一个可靠的套接字,它可以处理消息,并且具有明确定义的故障模式。

【问题讨论】:

  • 嗯。似乎一个可以使用一个路由器套接字来对抗外界调用这个S,并像这样工作:创建一个辅助套接字对用于进程内部通信。调用此 AB,将传出消息放入 A,然后轮询套接字联合 (S,B),如果 S,则从外部接收,或者如果 B,则将其放入 S。现在只有一个线程接触过 S ,或任何其他套接字,并且我们知道客户端标识符。

标签: python asynchronous networking zeromq


【解决方案1】:

我不了解 Python,但对于 C/C++,我会使用 zmq_poll()。有多种选择,具体取决于您的要求。

  • 使用zmq_poll() 等待来自客户端的消息。如果消息到达,则对其进行处理。也使用超时。当超时到期时,检查您是否需要向客户端发送消息并发送它们。
  • zmq_poll() 也可以等待通用文件描述符。当您有消息要发送给客户端时,您可以使用某种类型的文件描述符并从另一个进程或线程触发(写入)它。如果触发此文件描述符,则向客户端发送消息。
  • 在服务器内部使用 ZeroMQ 套接字。使用zmq_poll() 等待来自客户端和内部进程或线程的消息。如果内部套接字被触发,则向客户端发送消息。

您可以使用文件描述符或内部 ZeroMQ 套接字仅用于触发,但您也可以通过文件描述符或 ZeroMQ 套接字发送消息内容。

【讨论】:

  • 谢谢。好主意,我对他们的个人排名:1)真的不可行。如果延迟是我们关心的事情,并且延迟是 10 毫秒,我们应该以 100Hz 循环,以免大部分延迟来自这里。 2)好主意。不过,我正在使用 python,这要么是不可能的,要么是没有记录的,而且很难。 3)我最终使用的是什么。不过,仅通过触发器的想法是一个很大的改进。谢谢。
  • @Elmore 如果您认为答案对您或其他人有用,请考虑对其进行投票。
  • @Elmore:如果您认为您的解决方案可能对未来的读者足够有趣,并且与现有答案有所不同,请尽可能添加您自己的答案。此处欢迎自行回答问题。
【解决方案2】:

Q“ZeroMQ:如何构造简单的异步代理?”

这个概念建立在一些不受支持或不成立的假设之上:

a)
Python 线程实际上从不并发执行,它们被重新[SERIAL]-化为一系列独奏者执行块,并且在任何可预见的未来都将保持这种状态,因为永远&永远(因为 Guido van ROSSUM 已将此功能解释为防止碰撞的金字塔原因 - 用于此目的的 GIL 锁的详细信息是countless

b)
ZeroMQ 线程安全与使用阻塞模式进行操作无关。

c)
ZeroMQ PUB/SUB 原型确实执行了主题过滤,但在“海​​洋”的不同侧面有不同的版本:

在 v3.1 之前,订阅机制(又名 TOPIC 过滤器)是在 SUB 端处理的,因此这部分处理分配给所有 SUB -s(以所有涉及的传输类的统一广泛的数据流量为代价)并且没有任何惩罚,除了在PUB-side 上采购此类与数据流相关的工作负载...
从 v3.1 开始,TOPIC 过滤器在PUB 端进行处理,代价是这样的处理开销和内存分配,但节省了所有以前浪费的传输容量,稍后在@987654332 上实现@-side 消息与 TOPIC-filter 不匹配,将被丢弃。

在代码设计中使用.poll()-based & zmq.NOBLOCK-modes 的.recv()- & .send()-methods 将永远不会让一个模棱两可,在一个无法挽救的死锁等待状态下,并添加甚至可以设计一个轻量级的priority 驱动的软调度程序,以实现不同的相对优先级。

鉴于您在实时系统中的丰富经验,您可能希望阅读 this 以查看 ZeroMQ 框架属性。

【讨论】:

  • 嗯,感谢您的回答和提供的链接。改写我原来的问题:虽然 ZeroMQ 提供了几种不同的套接字类型,但考虑一组要求:1)客户端可能在 NAT 之后,因此不能自己托管例如 PULL 套接字,2)我们希望在服务器时立即向客户端发送紧急数据包知道它们,使客户端发起的 req-rep 无效。那么如何解决这个问题呢?我完全了解 Python 中的 GIL,但是并发的 recv- 和 send- 调用仍然会在测试中使解释器崩溃。
  • 另外,这里也问了一个类似的问题:stackoverflow.com/questions/59847939/… 你也在那里发帖。我得到的印象是你知道你的份额,但你的回复都没有真正回答任何问题。一个简单的例子就足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-25
  • 2020-02-07
  • 1970-01-01
相关资源
最近更新 更多