Возможно обмен данными в памяти между двумя отдельными процессами?
У меня есть сервер xmlrpc с использованием Twisted. На сервере хранится огромное количество данных, хранящихся в памяти. Возможно ли иметь второй, отдельный сервер xmlrpc, который может получить доступ к объекту в памяти на первом сервере?
Итак, serverA запускается и создает объект. serverB запускается и может считывать с объекта в serverA.
* РЕДАКТИРОВАТЬ *
Данные для совместного использования - это список из 1 миллиона кортежей.
Ответы
Ответ 1
Без глубокой и темной перезаписи основного времени выполнения Python (чтобы обеспечить форсирование распределителя, который использует данный сегмент разделяемой памяти и обеспечивает совместимые адреса между разрозненными процессами), нет возможности "обмениваться объектами в памяти" в любом общий смысл. Этот список будет содержать миллион адресов кортежей, каждый кортеж состоит из адресов всех его элементов, и каждый из этих адресов будет назначен pymalloc таким образом, который неизбежно будет варьироваться между процессами и распространяется по всей куче.
В любой системе, кроме Windows, можно создать подпроцесс, который имеет доступ только для чтения к объектам в родительском пространстве процесса... пока родительский процесс не изменит эти объекты. Это получилось при вызове os.fork()
, что на практике "моментальные снимки" все пространство памяти текущего процесса и запускает другой одновременный процесс копирования/моментального снимка. Во всех современных операционных системах это очень быстро благодаря подходу "копирование на запись": страницы виртуальной памяти, которые не изменяются ни одним из процессов после того, как вилка на самом деле не скопирована (доступ к тем же страницам не используется совместно); как только любой процесс изменяет любой бит на ранее разделяемой странице, poof, эта страница будет скопирована, а таблица страниц изменена, поэтому процесс модификации теперь имеет свою собственную копию, в то время как другой процесс все еще видит исходный.
Эта чрезвычайно ограниченная форма совместного использования в некоторых случаях может оставаться спасателем (хотя она крайне ограничена: помните, например, что добавление ссылки на общий объект считается как "изменение" этого объекта из-за количества ссылок, и так будет принудительно копировать страницу!)... кроме Windows, конечно, где он недоступен. С помощью этого единственного исключения (которое, как я думаю, не будет охватывать ваш случай использования) разделение графиков объектов, которое включает ссылки/указатели на другие объекты, в основном неосуществимо - и почти любые объекты, представляющие интерес для современных языков (включая Python) подпадает под эту классификацию.
В экстремальных (но достаточно простых) случаях можно получить совместное использование, отказавшись от представления собственной памяти таких графов объектов. Например, список из миллиона кортежей, каждый с шестнадцатью поплавками, может фактически быть представлен как единый блок с общей памятью 128 МБ - все 16M-поплавки в представлении IEEE с двойной точностью, заложенные до конца - с небольшой фиксацией сверху, чтобы "сделать это похожим", вы обращаетесь к вещам обычным способом (и, конечно же, не слишком мало-после-все-прокладки должны также заботиться о чрезвычайно волосатых проблемах синхронизации между процессами, которые обязательно возникнут;-). Это только становится более увядающим и более сложным оттуда.
Современные подходы к concurrency все более и более презирают подход "ничего общего" в пользу "ничего общего", когда задачи обмениваются сообщениями (даже в многоядерных системах с использованием потоков и общих адресных пространств, проблем синхронизации и производительность достигает HW с точки зрения кеширования, конвейера и т.д., когда большие области памяти активно модифицируются несколькими ядрами одновременно, отталкивают людей).
Например, модуль многопроцессорности в стандартной библиотеке Python в основном опирается на травление и отправку объектов туда и обратно, а не на совместное использование памяти (конечно, не в R/W-режиме!).
Я понимаю, что это не приветствуется новостями для OP, но если ему нужно заставить несколько процессоров работать, ему лучше подумать о том, чтобы иметь что-то, что они должны делиться, в тех местах, где они могут быть доступны и изменены передача сообщений - база данных, кластер memcache, выделенный процесс, который ничего не делает, но сохраняет эти данные в памяти и отправляет и получает их по запросу, и другие подобные архитектуры передачи сообщений.
Ответ 2
mmap.mmap(0, 65536, 'GlobalSharedMemory')
Я думаю, что тег ( "GlobalSharedMemory" ) должен быть одинаковым для всех процессов, желающих разделить одну и ту же память.
http://docs.python.org/library/mmap.html
Ответ 3
В Python имеется пара 1 сторонних библиотек, доступных для манипуляций с общей памятью низкого уровня:
Оба из них доступны через pip
[1] Другой пакет, shm, доступен, но устарел. См. эту страницу для сравнения библиотек.
shmwriter.c
#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);
}
shmreader.py
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
Ответ 4
Вы можете написать библиотеку C для создания и управления массивами разделяемой памяти для вашей конкретной цели, а затем использовать ctypes для доступа к ним с Python.
Или, поместите их в файловую систему в /dev/shm (это tmpfs). Вы бы сэкономили много усилий на разработку для очень небольших издержек производительности: чтение/запись из файловой системы tmpfs - это немного больше, чем memcpy.
Ответ 5
Вы можете использовать модуль Pipon Multiprocessing.
http://docs.python.org/library/multiprocessing.html#sharing-state-between-processes
Ответ 6
Почему бы не вставить общие данные на сервер memcache? то оба сервера могут получить к нему доступ довольно легко.
Ответ 7
Простой на самом деле. Вы можете просто использовать общую память. В этом примере создается список кортежей (python) на С++ и делится им с процессом python, который затем может использовать список кортежей. Чтобы использовать между двумя процессами Python, просто сделайте свой доступ как ACCESS_WRITE
в процессе отправителя и вызовите метод write
.
С++ (процесс отправителя):
#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)
Ответ 8
Почему бы просто не использовать базу данных для общих данных? У вас есть множество облегченных вариантов, в которых вам не нужно беспокоиться о проблемах concurrency: sqlite, любом из классов баз данных nosql/key-value и т.д.