如何从流中写入python中的共享内存?

时间:2012-11-21 05:51:29

标签: python sockets shared-memory

我有几个服务器的进程,每秒都会通过udp向我的本地端口2222发送数据。

我想读取这些数据并将其写入共享内存,因此可以有其他进程从共享内存中读取数据并执行操作。

我一直在阅读mmap,似乎我必须使用一个文件......我似乎无法理解为什么。

我有一个a.py从套接字读取数据,但是如何将其写入shm?

一旦写完,我需要写b.pyc.pyd.py等来阅读相同的内容并为其做些事情。

任何帮助或代码段都会有很大帮助。

2 个答案:

答案 0 :(得分:0)

首先,请注意,您尝试构建的内容不仅仅需要共享内存:如果a.py写入共享内存,那么一切都很好,但b.py将如何知道内存何时就绪并且可以从中读取?总而言之,通过不通过共享内存连接多个进程,而是通过其他一些机制来解决这个问题通常更简单。

mmap通常需要文件名的原因是它需要一个名称来连接多个进程。实际上,如果a.py和{{1}两者都调用b.py,系统如何知道这两个进程要求在它们之间共享内存,而不是一些不相关的mmap()?因为它们都z.py编辑了同一个文件还有一些特定于Linux的扩展名,它们的名称与文件名称不对应,但它更像是一个黑客恕我直言。)

也许最基本的替代机制是管道:它们通常在程序启动时通过shell的帮助连接。这就是以下工作方式(在Linux / Unix上):mmappython a.py | python b.py发送的任何输出都将发送到管道,管道的另一端是a.py的输入。您将编写b.py以便它侦听UDP套接字并将数据写入stdout和a.py,以便它从stdin读取以处理收到的数据。如果数据需要转到多个进程,您可以使用例如命名管道,它具有一个很好的(但特定于Bash)语法:b.py将使用两个参数启动python a.py >(python b.py) >(python c.py),这两个参数是可以打开和写入的伪文件的名称。写入第一个伪文件的任何内容都作为a.py的输入,类似地写入第二个伪文件的内容作为b.py的输入。

答案 1 :(得分:0)

mmap不是文件名,而是文件描述符。它执行所谓的存储器映射,即它将进程的虚拟存储器空间中的页面与由文件描述符表示的文件类对象的部分相关联。这是一个非常强大的操作,因为它允许您:

  • 只是作为内存中的数组访问文件的内容;
  • 访问特殊I / O硬件的存储器,例如,声卡的缓冲区或图形适配器的帧缓冲区(这是可能的,因为Unix中的文件解析器是抽象的,它们也可以引用设备节点而不是常规文件);
  • 通过执行同一对象的共享映射来共享进程之间的内存。

在Unix上使用共享内存的旧的POSIX前方法是使用System V IPC共享内存。首先,必须使用shmget(2)创建共享内存段,然后使用shmat(2)将其附加到进程。 SysV共享内存段(以及其他IPC对象)没有名称而是数字ID,因此提供了特殊的散列函数ftok(3),它将路径名字符串和项目ID整数的组合转换为数字键ID,但可能发生碰撞。

使用共享内存的现代POSIX方法是使用shm_open(2)打开类似文件的内存对象,使用ftruncate(2)将其大小调整为所需大小,然后再调整为mmap(2)。在这种情况下,内存映射的作用类似于来自SysV IPC API的shmat(2)调用,因为shm_open(2)创建初始大小为零的对象,所以必须进行截断。

(这些是C API的一部分; Python模块提供的或多或少的封装器围绕这些调用并且通常具有几乎相同的签名)

还可以通过在需要共享内存的所有进程中映射相同常规文件的内存来获取共享内存。事实上,Linux通过在特殊的tmpfs文件系统上创建文件来实现POSIX共享内存操作。 tmpfs驱动程序通过将包含文件内容的页面直接映射到执行mmap(2)的进程的地址空间来实现非常轻量级的内存映射。由于tmpfs表现为普通文件系统,因此您可以使用lscat和其他shell工具检查其内容。您甚至可以通过这种方式创建共享内存对象,也可以修改现有内存对象的内容。 tmpfs中的文件与常规文件系统文件之间的区别在于后者持久保存到存储介质(硬盘,网络存储,闪存驱动器等),偶尔会将更改刷新到此存储介质,而前者完全生活在RAM中。 Solaris还提供类似的基于RAM的文件系统,也称为tmpfs

在现代操作系统中,广泛使用存储器映射。可执行文件是内存映射的,以便提供那些包含可执行代码和静态数据的页面的内容。共享库也是内存映射的。这节省了物理内存,因为这些映射是共享的,例如,保存可执行文件或共享库内容的相同物理内存映射到每个进程的虚拟内存空间中。