我有一个来自几台服务器的进程,每秒通过 udp 向我的本地端口 2222 发送数据。
我想读取这些数据并将其写入共享内存,这样就可以有其他进程从共享内存中读取数据并对其执行操作。
我一直在阅读mmap
,似乎我必须使用一个文件......我似乎无法理解为什么。
我有一个a.py
从套接字读取数据的设备,但是如何将其写入 shm?
一旦写完,我需要写b.py
, c.py
,d.py
等来读取相同的 shm 并对它做一些事情。
任何帮助或代码片段都会有很大帮助。
我有一个来自几台服务器的进程,每秒通过 udp 向我的本地端口 2222 发送数据。
我想读取这些数据并将其写入共享内存,这样就可以有其他进程从共享内存中读取数据并对其执行操作。
我一直在阅读mmap
,似乎我必须使用一个文件......我似乎无法理解为什么。
我有一个a.py
从套接字读取数据的设备,但是如何将其写入 shm?
一旦写完,我需要写b.py
, c.py
,d.py
等来读取相同的 shm 并对它做一些事情。
任何帮助或代码片段都会有很大帮助。
mmap
不采用文件名,而是采用文件描述符。它执行所谓的内存映射,即将进程的虚拟内存空间中的页面与由文件描述符表示的类文件对象的部分相关联。这是一个非常强大的操作,因为它允许您:
在 Unix 上使用共享内存的旧的 pre-POSIX 方法是使用 System V IPC 共享内存。首先,必须使用创建共享内存段shmget(2)
,然后使用 将其附加到进程shmat(2)
。SysV 共享内存段(以及其他 IPC 对象)没有名称,而是数字 ID,因此ftok(3)
提供了特殊的哈希函数,它将路径名字符串和项目 ID 整数的组合转换为数字键 ID,但冲突是可能的。
使用共享内存的现代 POSIX 方法是用 来打开一个类似文件的内存对象,用shm_open(2)
调整它的大小,ftruncate(2)
然后再调整到mmap(2)
它。在这种情况下,内存映射的作用类似于shmat(2)
来自 SysV IPC API 的调用,并且截断是必要的,因为shm_open(2)
创建初始大小为零的对象。
(这些是 C API 的一部分;Python 模块提供的或多或少是围绕这些调用的薄包装器,并且通常具有几乎相同的签名)
也可以通过在所有需要共享内存的进程中对同一个常规文件进行内存映射来获得共享内存。事实上,Linux 通过在特殊tmpfs
文件系统上创建文件来实现 POSIX 共享内存操作。驱动程序通过tmpfs
将保存文件内容的页面直接映射到正在执行的进程的地址空间来实现非常轻量级的内存映射mmap(2)
。由于tmpfs
其行为与普通文件系统一样,您可以使用ls
,cat
和其他 shell 工具检查其内容。您甚至可以通过这种方式创建共享内存对象或修改现有对象的内容。文件中的区别tmpfs
一个常规的文件系统文件是后者被持久化到存储介质(硬盘、网络存储、闪存驱动器等),并且偶尔会刷新到这个存储介质,而前者完全存在于 RAM 中。Solaris 还提供类似的基于 RAM 的文件系统,也称为tmpfs
.
在现代操作系统中,内存映射被广泛使用。可执行文件是内存映射的,以提供这些页面的内容,这些页面包含可执行代码和静态数据。共享库也是内存映射的。这节省了物理内存,因为这些映射是共享的,例如,保存可执行文件或共享库的内容的相同物理内存被映射到每个进程的虚拟内存空间中。
First, note that what you're trying to build will require more than just shared memory: it's all well if a.py
writes to shared memory, but how will b.py
know when the memory is ready and can be read from? All in all, it is often simpler to solve this problem by connecting the multiple processes not via shared memory, but through some other mechanism.
(The reason for why mmap
usually needs a file name is that it needs a name to connect the several processes. Indeed, if a.py
and b.py
both call mmap()
, how would the system know that these two processes are asking for memory to be shared between them, and not some unrelated z.py
? Because they both mmap
ed the same file. There are also Linux-specific extensions to give a name that doesn't correspond to a file name, but it's more a hack IMHO.)
Maybe the most basic alternative mechanism is pipes: they are usually connected with the help of the shell when the programs are started. That's how the following works (on Linux/Unix): python a.py | python b.py
. Any output that a.py
sends goes to the pipe, whose other end is the input for b.py
. You'd write a.py
so that it listens to the UDP socket and writes the data to stdout, and b.py
so that it reads from stdin to process the data received. If the data needs to go to several processes, you can use e.g. named pipes, which have a nice (but Bash-specific) syntax: python a.py >(python b.py) >(python c.py)
will start a.py
with two arguments, which are names of pseudo-files that can be opened and written to. Whatever is written to the first pseudo-file goes as input for b.py
, and similarly what is written to the second pseudo-file goes as input for c.py
.