Python中使用ZeroMQ传递列表或字典。

16

在Python中,发送像列表或字典这样的对象到zeromq,应该采用什么正确/最佳方法?

如果我们使用PUB/SUB模式,在字符串的第一部分作为过滤器,会发生什么情况?

  • 我知道有多部分消息,但它们最初是为不同的目的而设计的。此外,您无法订阅所有第一个元素为特定字符串的消息。
7个回答

18

手动序列化

将数据转换为字符串,串联或其他操作处理数据。这种方法速度快,占用空间少,但需要付出工作和维护的成本,并且不够灵活。

如果其他语言想要读取这些数据,则需要再编写代码。不能DRY。

对于非常小的数据,可以使用此方法,但通常情况下这种方式所需的工作量并不值得,除非您正在寻求速度和内存效率,并且可以测量您的实现与其他实现相比有显著优势。

Pickle

速度慢,但可以序列化复杂对象,甚至可调用。它很强大,而且使用起来非常简单。

另一方面,可能会得到无法进行序列化的对象而破坏你的代码。此外,您无法与使用其他语言编写的库共享数据。

最终,格式不易读(难以调试)且非常冗长。

非常适合共享对象和任务,但不适合消息。

JSON

速度相当快,适用于简单到中等复杂的数据结构的简单实现。它很灵活,人类可以读取数据,并且数据可以轻松地在各种语言之间共享。

对于复杂数据,您需要编写一些代码。

除非您有非常特定的需求,否则这可能是功能和复杂性之间的最佳平衡。尤其是因为Python库中的最新实现采用了C语言,速度也很快。

XML

冗长、难以创建,在没有重量级库辅助的情况下维护起来很痛苦。速度慢。

除非有要求,否则建议避免使用。

最后

现在通常情况下,速度和空间效率都相对而言,并且您必须先回答以下问题:

  • 我需要什么效率?
  • 我愿意为此付出多少代价(金钱、时间、精力)?
  • 哪种解决方案适合我的当前系统?

这就是所有的要紧之处。

那个美好哲学时刻已经过去了,使用JSON吧。


Pickle比你展示的更糟糕,因为它强制你保持两边代码完全同步或在各处编写pickle helpers。更不用提安全方面的问题了。 - schlenk
@schlenk:实际上,同步对于所有类型的序列化都是真实的。每次更改格式时,您需要保持同步,除非您共享的最复杂的东西是字符串列表。如果是这样,使用pickle不需要同步代码也不会有问题。此外,就安全性而言,如果您是发送和接收消息的人,则没有问题。我们不是在谈论API。 - Bite code
好的讨论,但是没有提到过滤器。由于过滤器(setsocketopt)使用字符串,那么如何轻松地为对象设置过滤器呢?我希望答案不是“看看字符串长什么样子,然后使用它”。 - user989762
过滤器通常应用于路由键而不是数据内容。但是,如果您确实需要在内容上应用过滤器,JSON是最简单的方法,因为在整个消息传递链中实现解码/编码非常容易。 - Bite code

8

7
在zeroMQ中,消息只是一个二进制块,可以放置任何想要的内容。当您有一个具有多个部分的对象时,您需要先将其序列化为可在另一端反序列化的内容。最简单的方法是使用obj.repr(),它会生成一个字符串,在其他端可以执行该字符串以重新创建对象。但这不是最好的方法。
首先,应该尝试使用独立于语言的格式,因为迟早需要与其他语言编写的应用程序进行交互。JSON对象是一个很好的选择,因为它是一个可以被许多语言解码的字符串。然而,如果您要跨网络发送大量消息,则JSON对象可能不是最有效的表示形式。相反,您可能需要考虑像MSGPACK或Protobufs这样的格式。
如果需要PUB_SUB的主题标识符,则可以将其附加在开头。可以使用固定长度的主题,也可以在主题和实际消息之间放置一个分隔符。

6
在发送之前将其编码为JSON格式,在接收后将其解码为JSON格式。

您能详细解释一下吗?我对速度、优劣势以及相对于仅连接字符串(比如逗号分隔)的区别很感兴趣。 - Davoud Taghawi-Nejad
1
@DavoudTaghawi-Nejad:主要的优点是你不需要编写解析器。 - Fred Foo
1
@DavoudTaghawi-Nejad - 你会如何将对象表示为字符串?你会将其强制转换为对象的repr值,然后再进行eval操作吗?这种方法非常有限,并且取决于列表或字典中的对象而容易出现问题。 - jdi

4

还可以查看MessagePack

http://msgpack.org/

"它就像JSON一样,但更快速、更小巧"


2
如果您有兴趣查看示例,我发布了一个名为pyRpc的小包,展示了如何设置简单的Python RPC,使不同应用程序之间的服务得以暴露。它使用Python zeromq内置方法发送和接收Python对象(我认为这只是cPickle)。
链接:http://pypi.python.org/pypi/pyRpc/0.1https://github.com/justinfx/pyRpc 虽然我的示例使用了pyobj版本的send和receive调用,但您可以看到其他可用的版本,例如send_json、send_unicode... 除非您需要某种特定类型的序列化,否则您可以轻松使用方便的send/receive函数,该函数为您处理双方的序列化/反序列化。
链接:http://zeromq.github.com/pyzmq/api/generated/zmq.core.socket.html json可能是最快的,如果您需要比zeromq中提供的更快的速度,则可以手动使用cjson。如果您的重点是速度,那么这是一个不错的选择。但如果您知道只与其他Python服务通信,那么cPickle的好处在于它是一种本地Python序列化格式,可以给您带来许多控制权。您可以轻松定义要序列化的类,以您想要的方式进行序列化,并最终得到本地Python对象,而不是基本值。我相信如果需要,您也可以为json编写自己的对象钩子。

2

这个问题中有几个问题,但是关于发送对象/字典的最佳/正确方法,显然取决于具体情况。对于许多情况来说,JSON 是简单且大多数人熟悉的方式。要使其工作,我必须使用 send_stringrecv_string

# client.py

socket.send_string(json.dumps({'data': ['a', 'b', 'c']}))

# server.py

result = json.loads(socket.recv_string())

在文档中讨论 https://pyzmq.readthedocs.io/en/latest/unicode.html 相关的编程内容。


谢谢!帮我解决了在使用send()和recv()方法时遇到的Unicode问题。 - user2976612

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接