IT TIP

2 개의 개별 프로세스간에 인 메모리 데이터를 공유 할 수 있습니까?

itqueen 2020. 12. 28. 22:20
반응형

2 개의 개별 프로세스간에 인 메모리 데이터를 공유 할 수 있습니까?


Twisted를 사용하는 xmlrpc 서버가 있습니다. 서버에는 엄청난 양의 데이터가 메모리에 저장되어 있습니다. 첫 번째 서버의 메모리 내 개체에 액세스 할 수있는 별도의 보조 xmlrpc 서버를 실행할 수 있습니까?

따라서 serverA가 시작되고 객체를 생성합니다. serverB가 시작되고 serverA의 개체에서 읽을 수 있습니다.

* 편집하다 *

공유 할 데이터는 1 백만 개의 튜플 목록입니다.


(주어진 공유 메모리 세그먼트를 사용하고 서로 다른 프로세스간에 호환 가능한 주소를 보장하기 위해) Python 코어 런타임을 깊고 어둡게 다시 작성하지 않으면 일반적인 의미에서 "메모리의 객체를 공유"할 방법이 없습니다. 이 목록은 백만 개의 튜플 주소를 보유하고 각 튜플은 모든 항목의 주소로 구성되며 이러한 각 주소는 필연적으로 프로세스간에 달라지고 힙 전체에 퍼지는 방식으로 pymalloc에 ​​의해 할당됩니다.

Windows를 제외한 거의 모든 시스템에서 부모 프로세스가 해당 개체를 변경하지 않는 한 기본적으로 부모 프로세스 공간의 개체에 대한 읽기 전용 액세스 권한이있는 하위 프로세스를 생성 할 수 있습니다. 그것은 전화로 얻은os.fork(), 실제로는 현재 프로세스의 모든 메모리 공간을 "스냅 샷"하고 복사 / 스냅 샷에서 다른 동시 프로세스를 시작합니다. 모든 최신 운영 체제에서 이것은 "쓰기시 복사"접근 방식 덕분에 실제로 매우 빠릅니다. 포크 후 두 프로세스에 의해 변경되지 않은 가상 메모리 페이지는 실제로 복사되지 않습니다 (대신 동일한 페이지에 대한 액세스가 공유 됨). ; 어느 한 프로세스가 이전에 공유 된 페이지의 비트를 수정하자마자 해당 페이지가 복사되고 페이지 테이블이 수정되므로 수정 프로세스는 이제 자체 복사본을 가지지 만 다른 프로세스는 여전히 원본을 볼 수 있습니다.

이 극도로 제한된 형태의 공유는 어떤 경우에는 여전히 생명의 은인이 될 수 있습니다 (극히 제한적 임에도 불구하고 : 예를 들어 공유 객체에 대한 참조를 추가하는 것은 참조 횟수로 인해 해당 객체를 "변경"하는 것으로 간주되어 페이지를 강제 실행합니다. copy!) ... 물론 Windows에서는 사용할 수없는 경우를 제외하고. 이 단일 예외 (사용 사례를 다루지 않을 것 같음)를 제외하고는 다른 객체에 대한 참조 / 포인터를 포함하는 객체 그래프를 공유하는 것은 기본적으로 불가능하며 현대 언어 (Python 포함)에서 관심있는 거의 모든 객체 세트 이 분류에 속합니다.

극단적 인 (그러나 충분히 단순한) 경우에는 그러한 객체 그래프의 기본 메모리 표현을 포기함으로써 공유를 얻을 수 있습니다. 예를 들어, 각각 16 개의 부동 소수점이있는 백만 개의 튜플 목록은 실제로 128MB의 공유 메모리 단일 블록으로 표현 될 수 있습니다. 모든 16M 부동 소수점은 배정 밀도 IEEE 표현으로 끝이 나옵니다. 정상적 방식으로 문제를 처리하고있는 "처럼 보이게"하려면 (물론 그다지 작지 않은 심도 프로세스 간 동기화 문제를 처리해야합니다. 일어날 것이 확실합니다 ;-). 거기에서 더 털이 많고 복잡해집니다.

동시성에 대한 현대적인 접근 방식은 비공유 방식을 선호하는 공유 방식을 점점 더 무시하고 있습니다. 여기서 작업은 메시지 전달을 통해 통신합니다 (스레딩 및 공유 주소 공간을 사용하는 멀티 코어 시스템에서도 동기화 문제 및 성능이 HW에 영향을 미침). 많은 메모리 영역이 한 번에 여러 코어에 의해 능동적으로 수정되어 사람들을 밀어 내고있을 때 캐싱, 파이프 라인 중단 등의 측면에서 발생합니다.

예를 들어, Python의 표준 라이브러리에있는 다중 처리 모듈은 메모리 공유가 아니라 (확실히 R / W 방식이 아닙니다!-) 객체를 앞뒤로 피클 링하고 전송하는 데 주로 의존합니다.

나는 이것이 OP에 대한 반가운 소식이 아니라는 것을 알고 있지만 여러 프로세서를 작동시켜야 할 경우 메시지 전달을 통해 액세스하고 수정할 수있는 위치에 공유해야하는 모든 항목을 상주하는 관점에서 생각하는 것이 좋습니다. -데이터베이스, Memcache 클러스터, 데이터를 메모리에 보관하고 요청시 송수신하는 전용 프로세스 및 기타 메시지 전달 중심 아키텍처.


mmap.mmap(0, 65536, 'GlobalSharedMemory')

동일한 메모리를 공유하려는 모든 프로세스에 대해 태그 ( "GlobalSharedMemory")가 동일해야한다고 생각합니다.

http://docs.python.org/library/mmap.html


Python에서 저수준 공유 메모리 조작에 사용할 수있는 타사 라이브러리 가 두 있습니다.

  • sysv_ipc
    • > posix 비준수 시스템의 경우
  • posix_ipc
    • > cygwin과 함께 Windows에서 작동

둘 다 pip를 통해 사용할 수 있습니다.

[1] 다른 패키지 shm을 사용할 수 있지만 더 이상 사용되지 않습니다 . 라이브러리 비교는 이 페이지참조하십시오 .

C-Python 통신을위한 예제 코드 c / o Martin O'Hanlon :

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

특정 목적을 위해 공유 메모리 배열을 만들고 조작하는 C 라이브러리를 작성한 다음 ctypes를 사용하여 Python에서 액세스 할 수 있습니다.

또는 / dev / shm (tmpfs)의 파일 시스템에 저장합니다. 매우 적은 성능 오버 헤드로 많은 개발 노력을 절약 할 수 있습니다. tmpfs 파일 시스템의 읽기 / 쓰기는 memcpy에 불과합니다.


Python Multiprocessing 모듈을 사용할 수 있습니다.

http://docs.python.org/library/multiprocessing.html#sharing-state-between-processes


사실 간단합니다. 공유 메모리를 사용할 수 있습니다. 이 예제는 C ++로 튜플 (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)

공유 데이터를 Memcache 서버에 저장하지 않는 이유는 무엇입니까? 그러면 두 서버 모두 매우 쉽게 액세스 할 수 있습니다.


데이터가 단순히 튜플이고 이러한 데이터에 액세스하려는 경우

  • (nrows x tuplewidth) np.ndarrays 또는
  • n 1 일 np.ndarrays

그런 다음 memmap에 numpy의 래퍼를 사용하는 것이 좋습니다 .

내 이해는 다음과 같습니다.

  • numpy 배열을 원시 배열 내용을 보유하는 평면 memmap 파일로 저장합니다.
  • each process points an ndarray to the memmap file as its backing data. The documentation link shows how.

This works great for read-only data. If you want read-write, you'll need to uses the multiprocess locks to protect access.

Because memmap uses paging to load the data its a blazingly fast way to access large datasets from disk. In fact, I don't think modern OSs have any faster to loaded data from disk into memory than this -- no serialization is involved.


Why not just use a database for the shared data? You have a multitude of lightweight options where you don't need to worry about the concurrency issues: sqlite, any of the nosql/key-value breed of databases, etc.

ReferenceURL : https://stackoverflow.com/questions/1268252/possible-to-share-in-memory-data-between-2-separate-processes

반응형