2

我需要在 Scala 进程 (JeroMQ) 和 C 进程 (ZeroMQ) 之间建立通信。Scala 进程需要发送大型数组(每个数组 1 亿个浮点数)。这首先转换为 JSON 字符串,如下所示,我遇到了内存问题:

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at java.lang.StringCoding.encode(StringCoding.java:350)
    at java.lang.String.getBytes(String.java:939)
    at org.zeromq.ZMQ$Socket.send(ZMQ.java:1276)

1 亿个浮点数对应 762 MB。在我看来,序列化的 JSON 字符串变得越来越大。如果是,那么传输这种大小的数据的最佳方式是什么。

4

3 回答 3

1

正如ZeroMQ 的常见问题页面所建议的那样,您可以使用 Java(以及 Scala)和 C 都支持的任何数据编组格式。其中有很多(对于某些 C 支持是第三方的,尽管 C++ 通常不是) :协议缓冲区、MsgPack、Avro、Thrift、BSON 等。

于 2016-03-29T06:38:22.317 回答
1

首先,json 或任何其他数据序列化格式没有任何固有的特性使其不适用于大型数据集——您只需要确保您的机器有必要的资源来处理它。

某些格式可能比其他格式更节省内存,很可能二进制格式更适合您。

但是,根据您的情况(例如,如果您经常需要更新对整个数据集的访问权限),那么 user3666197 的答案可能更适合您的情况。

请允许我分开差异。

如果您的用例符合以下参数:

  1. 您需要不经常访问整个数据集
  2. 您可以处理较长的延迟时间
  3. 无法增加接收主机上的可用资源
  4. 不能(或者很难)在接收主机上创建持续更新的本地数据存储

...那么您最好的选择是简单地拆分数据集。看看你可以发送和解析多大的消息而不会耗尽资源,给自己一个 20-50% 的缓冲区(取决于你的容忍度),将你的数据集拆分成相应大小的块,发送块并重新组合它们. 这是在假设内存问题是由于在反序列化过程中同时处理内存中的序列化非序列化数据而导致的。如果这不是真的,并且未序列化的数据集本身太大而无法放入内存,那么您只需要分块处理数据而不重新组装它们。如果是这样,我会强烈建议找到一些方法来增加你的记忆资源,因为你生活在边缘。

于 2016-04-04T17:08:58.207 回答
1

尺寸?不,与运输哲学相关的约束很重要。

ZeroMQ 传输编排中还有一个比选择外部数据序列化器 SER/DES 策略更重要的问题。

没有人会禁止您尝试发送尽可能大BLOB的数据,而 JSON 装饰的字符串已经向您展示了这种方法的阴暗面,还有其他理由不继续这种方式。

ZeroMQ 毫无疑问是一个强大而强大的工具箱。仍然需要一些时间才能获得真正智能且高性能的代码部署所必需的洞察力,从而最大限度地利用这个强大的主力。

功能丰富的内部生态系统“幕后”的副作用之一是隐藏在消息传递概念中的不太为人所知的策略。

一个人可以发送任何大小合理的消息,但不能保证送达。它要么完全交付,要么根本没有任何东西,如上所述,没有任何保证。

哎哟?!

的,不保证。

基于这一核心零保证理念,在决定步骤和措施时应格外小心,如果您打算尝试将“技嘉BEAST”移来移去,则更应谨慎。

从这个意义上说,它可能会得到实际SUT测试的定量支持,即小型消息可能会传输(如果您确实仍然需要移动GB-s (参考上面的评论,在 OP 下)并且别无选择)整个将大量数据分割成更小的部分,并采用容易出错的重新组装措施,这导致GB比尝试使用哑力并指示代码将数据转储到任何东西上更快、更安全的端到端解决方案那里的资源实际上是可用的(ZeroMQ 的零拷贝原则不能也不会在这些努力中拯救你)。

有关另一个隐藏陷阱的详细信息,与不完全零拷贝实现有关,请阅读 Martin SUSTRIK,ZeroMQ 的共同之父,关于零拷贝“直到内核边界”的评论(因此,至少两倍的内存空间预期的分配......)。


最好的下一步?

虽然它并不能用几个SLOC-s 解决您的问题,但如果您认真地将您的智力投入到分布式处理中,最好的办法是阅读 Pieter HINTJEN 的可爱书“Code Connected, Vol.1”

是的,产生自己的洞察力需要一些时间,但这会在许多方面将您提升到另一个专业代码设计水平。值得时间。值得努力。

于 2016-03-29T07:47:34.933 回答