在 UNIX 进程之间交换适度大量数据的最佳方式是啥?

Posted

技术标签:

【中文标题】在 UNIX 进程之间交换适度大量数据的最佳方式是啥?【英文标题】:What's the best way to exchange moderately large amounts of data between UNIX processes?在 UNIX 进程之间交换适度大量数据的最佳方式是什么? 【发布时间】:2013-07-04 05:35:37 【问题描述】:

在 UNIX 进程之间交换中等大量数据(数兆字节,但不是千兆字节)的最佳方法是什么?

我想,应该是内存映射文件,因为大小限制seem tolerable enough.

我需要双向通信,所以普通管道无济于事。据我所知,对于套接字和 UDP,存在大小限制(另见 here)。 不确定,如果使用 TCP 在 fork() 的子进程和父进程之间进行通信是一个好主意。

阅读this等相关问题,有人推荐共享内存/mmap,也有人推荐sockets。

还有什么我应该研究的吗?例如,是否有一些更高级别的库通过提供例如帮助 IPC数据的XML序列化/反序列化?

由于 cmets 而编辑:

在我的特殊情况下,有一个父/控制器进程和几个子进程(不能使用线程)。控制器根据请求为孩子提供一些可能适合一个 UDP 包的关键数据。孩子对密钥数据进行操作,并根据密钥向控制器提供信息(信息大小可以为 10-100MB)。

问题:响应数据的大小,在密钥请求时通知父级的机制,同步 - 父级在传递给子级后必须从其列表中删除密钥,不应发生重复的密钥处理。

不得使用 Boost 和其他第三方库(很遗憾)。我也许可以使用 SunOS 5.10 系统提供的库。

【问题讨论】:

你可以有两个管道,每个方向一个。 什么算“大尺寸”?兆字节、千兆字节、兆兆字节,还是更大?普通文件或内存映射文件是合理的候选者...... en.wikipedia.org/wiki/Shared_memory#Support_on_UNIX_platforms 哦——那是宝贝大的东西。 :D 一次将修改多少数据?您是否需要在程序运行之间保留记录?写入模式是随机的吗?读取模式是随机的吗?读取模式是否与写入模式相关(您是否将其视为一个巨大的循环缓冲区,或者当写入者写入其他地方时,阅读器是否可以在整个地方阅读)? 不需要持久性,我可能会使用共享内存而不是内存映射文件(因为文件提供持久性)。您只需要小心协调对读写器之间任何给定区域的访问即可。您说数据流是双向的,因此您可能需要 A 通知 B 何时(何地)有新数据,以及 B 何时(何地)通知 A 有新数据的机制。 【参考方案1】:

套接字。您不必在使用锁或其他方式写入或读取内存时保护内存,以使其并行执行安全。另一个好处是,您可以非常轻松地将代码拆分为两个单独的可执行文件,并在不同的机器上执行这些文件,也可以使用套接字通信代码进行网络通信。

在我看来,主要的缺点是您必须找到一种方案来(反)序列化您的数据并将数据块拆分/组装到多个数据包中。

【讨论】:

我认为使用boost::serialization 可以减轻序列化/反序列化的负担。这在boost::mpi 中使用,可以也为 OP 的问题提供解决方案。 @juanchopanza 你是对的。我还没用过,所以没想到。 我想这取决于您所说的大型数据集的含义以及您需要它的速度。我会认为套接字接口太慢并且需要太多的请求/响应延迟。以及可能无法同时将整个数据集保存在内存中 2-3 次,并且必须重新流式传输数据,因为您之前必须丢弃它。 除了序列化:使用 UDP 会不会丢包?那么,在使用套接字的时候,你会推荐 TCP 吗? @bcml:如果您想通过网络传输数据,TCP 将是您的选择。否则,使用 Unix 域套接字 (en.wikipedia.org/wiki/Unix_domain_socket)【参考方案2】:

共享内存速度很快,但全部将协调访问内存的负担留给了您。您可能需要(至少)设置一个互斥锁,以确保在任何给定时间只有一个进程写入共享内存(显然,确保两个进程都正确使用该互斥锁)。

除此之外,您(再次,可能)需要在内存中设置一些结构,以便接收进程知道写入了哪些新数据、它驻留在哪里等。

套接字限制可以在单个数据包中发送的数据量,但不限制您可以发送的总数据量。另请注意,Unix 域套接字基本上是共享内存,所有协调都在内核中处理,因此它通常相当快。

有很多用于 IPC 序列化的库/协议——Boost Serialization、Sun XDR、Google 协议缓冲区等。鉴于您要交换大量数据,我会倾向于 倾向于 XML 以外的东西。 XML 编码和解析往往相对较慢,并且通常还会对数据进行相当大的扩展。

【讨论】:

【参考方案3】:

共享内存。您可以非常快速地读取/写入它,并且它始终可供双方使用,无需请求响应。

http://en.wikipedia.org/wiki/Shared_memory

更重要的是,您只需要保留一份数据集副本,因此您最终不会得到 2 个副本加上正在运行的数据 - 如果您买不起 2 个副本,您可能不得不流式传输使用其他解决方案多次使用相同的数据。

【讨论】:

但是如果你有两个进程修改共享内存,你必须协调访问,以免在进程同时修改同一个内存时发生冲突。 当然可以。但是您可以以极高的速度共享非常大的数据集。如果您知道它总是在同一个盒子上,那就值得权衡。

以上是关于在 UNIX 进程之间交换适度大量数据的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Unix进程小结进程间通信方式总结

在进程之间发送大量数据的最佳方法是啥?

进程的通信:共享存储消息传递和管道通信

进程间通信

C#:在多个进程和/或线程之间共享数据的最佳方式

进程间通信(IPC)介绍