Предоставление доступа к общей памяти после того, как дочерние процессы уже запущены

Как предоставить дочерним процессам доступ к данным в общей памяти, если данные доступны только после того, как дочерние процессы были созданы (с использованием многопроцессорности.Process )?

Я знаю многопроцессорность.sharedctypes.RawArray , но я не могу понять, как предоставить дочерним процессам доступ к RawArray который создается после того, как процессы уже запущены.

Данные генерируются родительским процессом, и количество данных заранее неизвестно.

Если бы не GIL, я бы вместо этого использовал threading, что сделало бы эту задачу немного проще. Использование реализации, отличной от CPython, не является вариантом.


Глядя под капотом muliprocessing.sharedctypes , похоже, что общие объекты ctype выделяются с использованием mmap памяти .

Поэтому этот вопрос действительно сводится к следующему: может ли дочерний процесс получить доступ к анонимно отображаемой памяти, если родительский родитель вызвал mmap() после того, как дочерний процесс был порожден?

Это несколько в духе того, что задается в этом вопросе , за исключением того, что в моем случае вызывающий mmap() является родительским процессом, а не дочерним процессом.


(Раскрыты)

Я создал свою собственную версию RawArray которая использует shm_open() под капотом. Получаемый общий массив ctypes может использоваться совместно с любым процессом, пока совпадает идентификатор ( tag ).

См. Этот ответ для получения более подробной информации и примера.

3 Solutions collect form web for “Предоставление доступа к общей памяти после того, как дочерние процессы уже запущены”

Ваша проблема звучит как идеальная подгонка для модулей posix_ipc или sysv_ipc , которые выставляют либо POSIX, либо SysV API для разделяемой памяти, семафоров и очередей сообщений. В матрице функций есть отличные рекомендации для выбора среди модулей, которые он предоставляет.

Проблема с анонимными областями mmap(2) заключается в том, что вы не можете легко делиться ими с другими процессами – если бы они были с файловой поддержкой, это было бы легко, но если вам действительно не нужен файл ни для чего другого, он чувствует глупо. Вы можете использовать флаг CLONE_VM для системного вызова clone(2) если это было на C, но я не хотел бы использовать его с интерпретатором языка, который, вероятно, делает предположения о безопасности памяти. (Это было бы немного опасно даже на C, так как программисты по обслуживанию через пять лет могут также быть шокированы поведением CLONE_VM .)

Но SysV и более новые сопоставления общей памяти POSIX позволяют даже несвязанным процессам присоединяться и отделяться от общей памяти по идентификатору, поэтому все, что вам нужно сделать, это обмениваться идентификатором с процессами, которые создают сопоставления с процессами, которые потребляют сопоставления, а затем когда вы манипулируете данными в сопоставлениях, они доступны для всех процессов одновременно без каких-либо дополнительных служебных операций синтаксического анализа. Функция shm_open(3) возвращает int которая используется в качестве дескриптора файла в последующих вызовах ftruncate(2) а затем mmap(2) , поэтому другие процессы могут использовать сегмент разделяемой памяти без создания файла в файловой системе – и эта память будет сохраняться, даже если все процессы, использующие ее, завершатся. (Немного странно для Unix, возможно, но это гибко.)

Отказ от ответственности: я являюсь автором вопроса.

В конечном итоге я использовал модуль posix_ipc для создания собственной версии RawArray . Я использовал в основном posix_ipc.SharedMemory который вызывает shm_open() под капотом.

Моя реализация ( ShmemRawArray ) предоставляет те же функции, что и RawArray но требует два дополнительных параметра – tag который однозначно идентифицирует область разделяемой памяти, и флаг create чтобы определить, следует ли нам создать новый сегмент разделяемой памяти или подключиться к существующей.

Вот копия, если кому-то интересно: https://gist.github.com/1222327

 ShmemRawArray(typecode_or_type, size_or_initializer, tag, create=True) 

Примечания по использованию:

  • Первые два аргумента ( typecode_or_type и size_or_initializer ) должны работать так же, как и с RawArray .
  • Общий массив доступен любому процессу, если tag совпадает.
  • Сегмент разделяемой памяти отсоединяется, когда объект происхождения (возвращаемый ShmemRawArray(..., create=True) ) удаляется
  • Создание общего массива с использованием tag который в настоящее время существует, вызовет ExistentialError
  • Доступ к общему массиву с использованием tag , который не существует (или тот, который был отсоединен), также приведет к созданию ExistentialError

SSCCE (Short, Self Contained, Compilable Example), показывающий его в действии.

 #!/usr/bin/env python2.7 import ctypes import multiprocessing from random import random, randint from shmemctypes import ShmemRawArray class Point(ctypes.Structure): _fields_ = [ ("x", ctypes.c_double), ("y", ctypes.c_double) ] def worker(q): # get access to ctypes array shared by parent count, tag = q.get() shared_data = ShmemRawArray(Point, count, tag, False) proc_name = multiprocessing.current_process().name print proc_name, ["%.3f %.3f" % (dx, dy) for d in shared_data] if __name__ == '__main__': procs = [] np = multiprocessing.cpu_count() queue = multiprocessing.Queue() # spawn child processes for i in xrange(np): p = multiprocessing.Process(target=worker, args=(queue,)) procs.append(p) p.start() # create a unique tag for shmem segment tag = "stack-overflow-%d" % multiprocessing.current_process().pid # random number of points with random data count = randint(3,10) combined_data = [Point(x=random(), y=random()) for i in xrange(count)] # create ctypes array in shared memory using ShmemRawArray # - we won't be able to use multiprocssing.sharectypes.RawArray here # because children already spawned shared_data = ShmemRawArray(Point, combined_data, tag) # give children info needed to access ctypes array for p in procs: queue.put((count, tag)) print "Parent", ["%.3f %.3f" % (dx, dy) for d in shared_data] for p in procs: p.join() 

Выполнение этого результата приводит к следующему результату:

 [me@home]$ ./shmem_test.py Parent ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110'] Process-1 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110'] Process-2 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110'] Process-3 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110'] Process-4 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110'] 

Я думаю, вы ищете модуль mmap

относительно сериализации данных этот вопрос ответ конечно, если вы надеетесь избежать копирования, у меня нет решения

РЕДАКТИРОВАТЬ

на самом деле вы можете использовать модуль nonstdlib _mutliprocessing в CPython 3.2, чтобы иметь адрес объекта mmap и использовать его с помощью_пакета объекта ctypes. Это то, что на самом деле то, что делает RawArray, на самом деле, конечно, вы не должны пытаться изменять размер mmap объект, так как адрес mmap может измениться в этом случае

 import mmap import _multiprocessing from ctypes import Structure,c_int map = mmap.mmap(-1,4) class A(Structure): _fields_ = [("x", c_int)] x = _multiprocessing.address_of_buffer(map) b=A.from_address(x[0]) bx = 256 >>> map[0:4] '\x00\x01\x00\x00' 

чтобы выставить память после создания ребенка, вам нужно сопоставить свою память с реальным файлом, который вызывает

 map = mmap.mmap(open("hello.txt", "r+b").fileno(),4) 
  • Как легко хранить удобные для чтения на python структуры данных только для чтения в общей памяти
  • Создайте новую obj с функцией deepcopy, но с новой переменной share obj со старым obj
  • Python - лучший язык программирования в мире.