You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过ZMQ发送Pickle5带外缓冲区序列化对象无额外内存拷贝?

用Pickle Protocol 5 + ZMQ零拷贝发送带外缓冲区数据

核心思路

利用ZMQ的**多部分消息(Multipart Messages)**特性,将Pickle的主序列化数据和所有带外缓冲区一次性发送,同时通过zmq.Frame实现零拷贝,避免不必要的内存复制和多次send()调用。

实现步骤与代码示例

发送端代码

import zmq
import pickle
from io import BytesIO

# 假设persons是你要序列化的自定义对象集合
persons = [...]

# 使用Pickle Protocol 5序列化,分离主数据和带外缓冲区
buf = BytesIO()
pickler = pickle.Pickler(buf, protocol=5)
pickler.dump(persons)
main_pickle_data = buf.getvalue()
external_buffers = pickler.buffers

# 初始化ZMQ套接字
ctx = zmq.Context()
sender = ctx.socket(zmq.PUSH)
sender.connect("tcp://localhost:5555")

# 构建零拷贝的多部分消息
message_parts = []
# 主序列化数据用Frame包装,copy=False表示不拷贝内存
message_parts.append(zmq.Frame(main_pickle_data, copy=False))
# 逐个添加带外缓冲区,同样用零拷贝Frame
for buf in external_buffers:
    message_parts.append(zmq.Frame(buf, copy=False))

# 一次性发送所有消息部分
sender.send_multipart(message_parts)

接收端代码

import zmq
import pickle

# 初始化ZMQ套接字
ctx = zmq.Context()
receiver = ctx.socket(zmq.PULL)
receiver.bind("tcp://localhost:5555")

# 一次性接收所有多部分消息
received_parts = receiver.recv_multipart()

# 拆分主数据和带外缓冲区
main_data = received_parts[0]
buffers = received_parts[1:]

# 反序列化,传入带外缓冲区
restored_persons = pickle.loads(main_data, buffers=buffers)

关键细节说明

  • 零拷贝实现:zmq.Frame(data, copy=False)会让ZMQ直接引用原始内存块发送,不做额外拷贝。注意发送期间不要修改原始的main_pickle_data和external_buffers,否则会导致传输数据损坏。
  • 多部分消息的顺序:Pickle生成的带外缓冲区顺序必须和反序列化时传入的顺序严格一致,直接按pickler.buffers的顺序添加到消息部分即可保证正确性。
  • 缓冲区类型兼容:如果你的带外缓冲区是numpy数组、memoryview或其他buffer-like对象,都可以直接传入zmq.Frame,无需转换为bytes(避免拷贝)。

内容的提问来源于stack exchange,提问作者Cypher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:25:25