我有一个使用Twisted的xmlrpc服务器。 服务器存储着大量数据的内存。是否可能运行第二个独立的xmlrpc服务器,并能访问第一个服务器中的内存对象?
因此,serverA启动并创建一个对象。 serverB启动并可以从serverA中读取对象。
* 编辑 *
要共享的数据是1百万个元组的列表。
我有一个使用Twisted的xmlrpc服务器。 服务器存储着大量数据的内存。是否可能运行第二个独立的xmlrpc服务器,并能访问第一个服务器中的内存对象?
因此,serverA启动并创建一个对象。 serverB启动并可以从serverA中读取对象。
* 编辑 *
要共享的数据是1百万个元组的列表。
如果不对Python核心运行时进行深度和黑暗的重写(以允许强制使用给定共享内存段的分配器并确保不同进程之间的兼容地址),则无法在一般意义上“共享内存中的对象”。那个列表将保存一百万个元组的地址,每个元组由其所有项的地址组成,这些地址都必须由pymalloc分配,在各个进程之间必然会有所变化,并且在整个堆中扩散。
除Windows外,几乎在所有系统上,可以生成一个子进程,该子进程基本上具有只读访问父进程空间中的对象...只要父进程不修改这些对象。通过调用os.fork()
来实现这一点,在实践中,“快照”当前进程的所有内存空间,并在副本/快照上启动另一个同时进程。在所有现代操作系统上,这实际上非常快,因为采用了“写时复制”的方法:在fork后,未被任何进程修改的虚拟内存页面不会真正复制(相反,两个进程都访问同一页面); 只要任一进程修改先前共享的页面中的任何位,poof,该页面就会被复制,并修改页表,因此修改进程现在具有自己的副本,而其他进程仍然看到原始进程。
这种极其有限的共享形式在某些情况下仍然可能挽救生命(尽管它非常有限:例如,请记住将引用添加到共享对象中会计为修改该对象,由于引用计数,因此会强制进行页面复制!)...当然,在Windows上除外,因为它不可用。除此之外(我认为不适用于您的用例),包括指向其他对象的引用/指针的对象图的共享基本上是不可行的 - 并且在现代语言(包括Python)中任何感兴趣的对象集都属于此类别。
在极端(但足够简单)的情况下,可以通过放弃对象图的本地内存表示来实现共享。例如,一个包含一百万个元组的列表,每个元组都有十六个浮点数,实际上可以表示为一个大小为128MB的共享内存块——所有16M个双精度IEEE表示的浮点数都排成一行,顶部还有一个小的“垫片”,以“使其看起来”像是正常访问对象(当然,这个不太小的垫片还必须处理极其复杂的跨进程同步问题;-))。从那里开始,情况只会变得更加棘手和复杂。mmap.mmap(0, 65536, 'GlobalSharedMemory')
我认为标签("GlobalSharedMemory")必须对所有希望共享相同内存的进程保持一致。
http://docs.python.org/library/mmap.htmlmultiprocessing
模块可以提供一些关于跨进程数据共享的见解。 - Joe Koberg有一些第三方库可用于Python中的低级共享内存操作:
这两个库都可以通过pip获取。
[1] 还有另一个shm包,但已经弃用。请参考此页面进行库的比较。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(int argc, const char **argv)
{
int shmid;
// give your shared memory an id, anything will do
key_t key = 123456;
char *shared_memory;
// Setup shared memory, 11 is the size
if ((shmid = shmget(key, 11, IPC_CREAT | 0666)) < 0)
{
printf("Error getting shared memory id");
exit(1);
}
// Attached shared memory
if ((shared_memory = shmat(shmid, NULL, 0)) == (char *) -1)
{
printf("Error attaching shared memory id");
exit(1);
}
// copy "hello world" to shared memory
memcpy(shared_memory, "Hello World", sizeof("Hello World"));
// sleep so there is enough time to run the reader!
sleep(10);
// Detach and remove shared memory
shmdt(shmid);
shmctl(shmid, IPC_RMID, NULL);
}
import sysv_ipc
# Create shared memory object
memory = sysv_ipc.SharedMemory(123456)
# Read value from shared memory
memory_value = memory.read()
# Find the 'end' of the string and strip
i = memory_value.find('\0')
if i != -1:
memory_value = memory_value[:i]
print memory_value
在 Python 3.8 中,您可以使用 shared_memory
。
其实很简单。你可以使用共享内存。这个例子在C++中创建了一个元组列表 (python),并将其与一个Python进程共享,以便Python进程可以使用这个元组列表。如果要在两个Python进程之间使用,只需在发送进程上将访问权限设为ACCESS_WRITE
,然后调用write
方法。
C++(发送进程):
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#define BUF_SIZE 256
TCHAR szName[]=TEXT("Global\\MyFileMappingObject");
TCHAR szMsg[]=TEXT("[(1, 2, 3), ('a', 'b', 'c', 'd', 'e'), (True, False), 'qwerty']");
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
CloseHandle(hMapFile);
return 1;
}
CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
_getch();
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
Python(接收进程):
import mmap
shmem = mmap.mmap(0,256,"Global\\MyFileMappingObject",mmap.ACCESS_READ)
msg_bytes = shmem.read()
msg_utf16 = msg_bytes.decode("utf-16")
code = msg_utf16.rstrip('\0')
yourTuple = eval(code)
如果您的数据只是元组,并且您愿意将其作为
np.ndarray
s,或者np.ndarrays
访问,则强烈建议使用numpy的memmap包装器。
我的理解是:
这对于只读数据非常有效。 如果您想要读写,则需要使用多进程锁来保护访问。
因为memmap使用分页加载数据,所以它是从磁盘访问大型数据集的绝佳快速方式。实际上,我认为现代操作系统没有比这更快地将数据从磁盘加载到内存中的方法--不涉及序列化。