PyZMQ 是不是为每个新的客户端连接处理创建线程?

Posted

技术标签:

【中文标题】PyZMQ 是不是为每个新的客户端连接处理创建线程?【英文标题】:Does PyZMQ handle creating threads for each new client connection?PyZMQ 是否为每个新的客户端连接处理创建线程? 【发布时间】:2012-10-29 15:11:03 【问题描述】:

我正在使用 PyZMQ 创建一个请求/回复服务器,并且我试图确定为每个新客户端连接创建线程的行为是否由 PyZMQ 自动处理。最终,我试图弄清楚来自一个需要很长时间才能回复的客户端的请求是否会阻止来自所有其他客户端的请求。

通常,我会在 Python 套接字实例上调用 accept,阻塞直到建立新连接,然后在单独的线程中处理任何新连接。但是,PyZMQ 套接字似乎不支持这样的工作流。那么,这在 PyZMQ 中是如何处理的呢?如果 PyZMQ REP 套接字有多个连接到它的客户端,它如何正确地将回复路由回发出请求的客户端?而且,我该如何设计我的代码,以便在客户端发出长时间运行的请求时不会阻止来自其他客户端的请求?

我知道我可以使用 PyZMQ 提供的基于 Tornado 的 EventLoop,我只是想更好地了解如果不能选择它会如何工作。

【问题讨论】:

【参考方案1】:

ZeroMQ 公开为“类固醇上的套接字”,但还有另一种实现通信的方法。

首先,忘记连接传统套接字中对等点的线。在 0mq 中,您有一个“量子传送器”,它将您的消息从一段代码传递到另一段代码,对您隐藏实际的传递工作。你不能只问 0mq 有多少客户端连接到套接字或者你是否有客户端。因此,ZeroMQ 不能用作套接字的替代品。

相反,0mq 给了你一顶魔术师帽子,你可以从中取出一些白兔。想象一下,那顶帽子的底部与一个巨大的管道网络相连,另一边有多个奇妙的工厂。这些工厂有时会送一些东西到你的帽子上,当你从帽子里拿出来时,你会发现自己手里拿着一只兔子,或者一束鲜花或其他东西。除非该东西上有明确的标签(即多部分消息的一部分指向消息的来源),否则您无法确定该东西是从哪个工厂发送的。

从帽子中取出兔子后,您可能想要发回一些东西,而 0mq 将针对不同的套接字类型表现不同。对于 REP 套接字,它将直接向消息源发送答案,因为 DEALER 将在连接的对等点之间循环回答,而 ROUTER 在接收消息时为您提供对对等点的确切内部地址的大量了解,并允许您在发送消息时设置明确的目的地。

总而言之,如果您想为每个通信客户端设置一个单独的线程,您需要以下内容:

客户应明确表明自己的身份。 在服务器上,您运行一个线程(调度程序)来接收消息、从中获取客户端身份并选择一个线程进行处理。 Dispatcher 将此消息发送到线程(或派生一个)并继续为传入消息流提供服务。 线程接收消息,对其进行处理并通过调度程序(如果需要)向客户端发送答案。 调度程序将应答路由到客户端。

这是一种在记住经典套接字知识的情况下实现“zeromq 上的多客户端套接字服务器”的方法。

但这不是解决问题的 0mq 方法。

在 0mq 中,您可以将处理逻辑放在一个线程中(上面示例中的调度程序)并将其实现为循环 receive request -> process -> send answer -> receive ...。当处理时间不是问题时非常适合。但是当它是,0mq 风格的解决方案涉及客户端和工作人员(执行实际工作)之间的任务队列代理。然后,broker逻辑比上面提到的receive-answer循环稍微复杂一点,worker的实现方式也是一样的。请参阅 zguide 中的示例 - A Request-Reply Message Broker

【讨论】:

长答案简短:没有一种简单的方法可以将每个连接与其自己的线程/greenlet 相关联吗?真的吗?

以上是关于PyZMQ 是不是为每个新的客户端连接处理创建线程?的主要内容,如果未能解决你的问题,请参考以下文章

javaNIO通信

node.js特点单线程

01-BIO通讯模型

将 CSocket 传递给 std::thread

Node.js知识点整理之----简介

几种 IO编程比较