multiprocessing.shared_memory
— Общая память для прямого доступа между процессами¶
Исходный код: Lib/multiprocessing/shared_memory.py
Добавлено в версии 3.8.
Этот модуль предоставляет класс SharedMemory
для выделения и управления разделяемой памятью, доступ к которой осуществляется одним или несколькими процессами на многоядерном или симметричном многопроцессорном компьютере (SMP). Для облегчения управления жизненным циклом совместно используемой памяти, особенно в различных процессах, в модуле multiprocessing.managers
также предусмотрен подкласс BaseManager
, SharedMemoryManager
.
В этом модуле разделяемая память относится к блокам общей памяти в стиле POSIX (хотя и не обязательно реализована явно как таковая) и не относится к «распределенной общей памяти». Этот тип разделяемой памяти позволяет отдельным процессам потенциально выполнять чтение и запись в общую (или совместно используемую) область энергозависимой памяти. Обычно процессы ограничены доступом только к своему собственному пространству памяти процесса, но общая память позволяет обмениваться данными между процессами, избегая необходимости отправлять сообщения между процессами, содержащими эти данные. Совместное использование данных непосредственно через память может обеспечить значительное повышение производительности по сравнению с совместным использованием данных через диск, сокет или другие средства связи, требующие сериализации/десериализации и копирования данных.
- class multiprocessing.shared_memory.SharedMemory(name=None, create=False, size=0)¶
Создайте экземпляр класса
SharedMemory
для создания нового блока общей памяти или присоединения к существующему блоку общей памяти. Каждому блоку общей памяти присваивается уникальное имя. Таким образом, один процесс может создать блок общей памяти с определенным именем, а другой процесс может подключиться к тому же блоку общей памяти, используя то же имя.Как ресурс для обмена данными между процессами, блоки общей памяти могут пережить исходный процесс, который их создал. Когда одному процессу больше не нужен доступ к блоку общей памяти, который все еще может понадобиться другим процессам, следует вызвать метод
close()
. Когда блок общей памяти больше не нужен какому-либо процессу, следует вызвать методunlink()
, чтобы обеспечить надлежащую очистку.- Parameters:
name (str | None) – Уникальное имя для запрашиваемой общей памяти, указанное в виде строки. При создании нового блока общей памяти, если в качестве имени указано
None
(значение по умолчанию), будет сгенерировано новое имя.create (bool) – Определяет, будет ли создан новый блок общей памяти (
True
) или будет подключен существующий блок общей памяти (False
).size (int) – Требуемое количество байт при создании нового блока общей памяти. Поскольку некоторые платформы предпочитают выделять блоки памяти в зависимости от размера страницы памяти этой платформы, точный размер блока общей памяти может быть больше или равен запрашиваемому размеру. При подключении к существующему блоку общей памяти параметр size игнорируется.
- close()¶
Закройте доступ к общей памяти из этого экземпляра. Чтобы обеспечить надлежащую очистку ресурсов, все экземпляры должны вызывать
close()
, как только экземпляр больше не нужен. Обратите внимание, что вызовclose()
не приводит к уничтожению самого блока общей памяти.
- unlink()¶
Запросите удаление базового блока общей памяти. Чтобы обеспечить надлежащую очистку ресурсов,
unlink()
должен вызываться один раз (и только один раз) во всех процессах, которым требуется блок общей памяти. После запроса на уничтожение блок общей памяти может быть немедленно уничтожен, а может и не быть уничтожен, и это поведение может отличаться в зависимости от платформы. Попытки доступа к данным внутри блока общей памяти после вызоваunlink()
могут привести к ошибкам доступа к памяти. Примечание: последний процесс, освобождающий свой доступ к блоку общей памяти, может вызыватьunlink()
иclose()
в любом порядке.
- buf¶
Просмотр в памяти содержимого блока общей памяти.
- name¶
Доступ только для чтения к уникальному имени блока общей памяти.
- size¶
Доступ только для чтения к размеру блока общей памяти в байтах.
Следующий пример демонстрирует низкоуровневое использование экземпляров SharedMemory
:
>>> from multiprocessing import shared_memory
>>> shm_a = shared_memory.SharedMemory(create=True, size=10)
>>> type(shm_a.buf)
<class 'memoryview'>
>>> buffer = shm_a.buf
>>> len(buffer)
10
>>> buffer[:4] = bytearray([22, 33, 44, 55]) # Modify multiple at once
>>> buffer[4] = 100 # Modify single byte at a time
>>> # Attach to an existing shared memory block
>>> shm_b = shared_memory.SharedMemory(shm_a.name)
>>> import array
>>> array.array('b', shm_b.buf[:5]) # Copy the data into a new array.array
array('b', [22, 33, 44, 55, 100])
>>> shm_b.buf[:5] = b'howdy' # Modify via shm_b using bytes
>>> bytes(shm_a.buf[:5]) # Access via shm_a
b'howdy'
>>> shm_b.close() # Close each SharedMemory instance
>>> shm_a.close()
>>> shm_a.unlink() # Call unlink only once to release the shared memory
Следующий пример демонстрирует практическое использование класса SharedMemory
с NumPy arrays, получая доступ к одному и тому же классу numpy.ndarray
из двух разных оболочек Python:
>>> # In the first Python interactive shell
>>> import numpy as np
>>> a = np.array([1, 1, 2, 3, 5, 8]) # Start with an existing NumPy array
>>> from multiprocessing import shared_memory
>>> shm = shared_memory.SharedMemory(create=True, size=a.nbytes)
>>> # Now create a NumPy array backed by shared memory
>>> b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
>>> b[:] = a[:] # Copy the original data into shared memory
>>> b
array([1, 1, 2, 3, 5, 8])
>>> type(b)
<class 'numpy.ndarray'>
>>> type(a)
<class 'numpy.ndarray'>
>>> shm.name # We did not specify a name so one was chosen for us
'psm_21467_46075'
>>> # In either the same shell or a new Python shell on the same machine
>>> import numpy as np
>>> from multiprocessing import shared_memory
>>> # Attach to the existing shared memory block
>>> existing_shm = shared_memory.SharedMemory(name='psm_21467_46075')
>>> # Note that a.shape is (6,) and a.dtype is np.int64 in this example
>>> c = np.ndarray((6,), dtype=np.int64, buffer=existing_shm.buf)
>>> c
array([1, 1, 2, 3, 5, 8])
>>> c[-1] = 888
>>> c
array([ 1, 1, 2, 3, 5, 888])
>>> # Back in the first Python interactive shell, b reflects this change
>>> b
array([ 1, 1, 2, 3, 5, 888])
>>> # Clean up from within the second Python shell
>>> del c # Unnecessary; merely emphasizing the array is no longer used
>>> existing_shm.close()
>>> # Clean up from within the first Python shell
>>> del b # Unnecessary; merely emphasizing the array is no longer used
>>> shm.close()
>>> shm.unlink() # Free and release the shared memory block at the very end
- class multiprocessing.managers.SharedMemoryManager([address[, authkey]])¶
Подкласс
multiprocessing.managers.BaseManager
, который может использоваться для управления блоками общей памяти в разных процессах.Вызов
start()
в экземпляреSharedMemoryManager
приводит к запуску нового процесса. Единственной целью этого нового процесса является управление жизненным циклом всех созданных с его помощью блоков общей памяти. Чтобы запустить освобождение всех блоков общей памяти, управляемых этим процессом, вызовитеshutdown()
для экземпляра. Это запускает вызовunlink()
для всех объектовSharedMemory
, управляемых этим процессом, а затем останавливает сам процесс. СоздаваяSharedMemory
экземпляров с помощьюSharedMemoryManager
, мы избавляемся от необходимости вручную отслеживать и запускать освобождение ресурсов общей памяти.Этот класс предоставляет методы для создания и возврата экземпляров
SharedMemory
, а также для создания объекта, подобного списку (ShareableList
), поддерживаемого общей памятью.Обратитесь к
BaseManager
для описания унаследованных необязательных входных аргументов address и authkey и того, как они могут использоваться для подключения к существующей службеSharedMemoryManager
из других процессов.- SharedMemory(size)¶
Создайте и верните новый объект
SharedMemory
с указанным размером в байтах.
- ShareableList(sequence)¶
Создайте и верните новый объект
ShareableList
, инициализированный значениями из входной последовательности *.
Следующий пример демонстрирует основные механизмы SharedMemoryManager
:
>>> from multiprocessing.managers import SharedMemoryManager
>>> smm = SharedMemoryManager()
>>> smm.start() # Start the process that manages the shared memory blocks
>>> sl = smm.ShareableList(range(4))
>>> sl
ShareableList([0, 1, 2, 3], name='psm_6572_7512')
>>> raw_shm = smm.SharedMemory(size=128)
>>> another_sl = smm.ShareableList('alpha')
>>> another_sl
ShareableList(['a', 'l', 'p', 'h', 'a'], name='psm_6572_12221')
>>> smm.shutdown() # Calls unlink() on sl, raw_shm, and another_sl
В следующем примере показан потенциально более удобный шаблон для использования объектов SharedMemoryManager
с помощью инструкции with
, чтобы гарантировать, что все блоки общей памяти будут освобождены после того, как они больше не понадобятся:
>>> with SharedMemoryManager() as smm:
... sl = smm.ShareableList(range(2000))
... # Divide the work among two processes, storing partial results in sl
... p1 = Process(target=do_work, args=(sl, 0, 1000))
... p2 = Process(target=do_work, args=(sl, 1000, 2000))
... p1.start()
... p2.start() # A multiprocessing.Pool might be more efficient
... p1.join()
... p2.join() # Wait for all work to complete in both processes
... total_result = sum(sl) # Consolidate the partial results now in sl
При использовании SharedMemoryManager
в инструкции with
все блоки общей памяти, созданные с помощью этого менеджера, освобождаются, когда блок кода инструкции with
завершает выполнение.
- class multiprocessing.shared_memory.ShareableList(sequence=None, *, name=None)¶
Предоставьте изменяемый объект, подобный списку, в котором все значения, хранящиеся внутри, хранятся в общем блоке памяти. Это ограничивает сохраняемые значения следующими встроенными типами данных:
int
(64-разрядная версия со знаком)str
(менее 10 миллионов байт каждый в кодировке UTF-8)bytes
(менее 10 миллионов байт каждый)None
Он также заметно отличается от встроенного типа
list
тем, что эти списки не могут изменять свою общую длину (т.е. нетappend()
,insert()
, и т.д.) и не поддерживают динамическое создание новых экземпляровShareableList
с помощью нарезки.последовательность используется для заполнения нового
ShareableList
, полного значений. Установите значениеNone
, чтобы вместо этого присоединить к уже существующемуShareableList
по его уникальному имени в общей памяти.имя - это уникальное имя для запрашиваемой общей памяти, как описано в определении для
SharedMemory
. При подключении к существующемуShareableList
укажите уникальное имя его блока общей памяти, оставив значение sequence равнымNone
.Примечание
Известная проблема существует для значений
bytes
иstr
. Если они заканчиваются на\x00
нулевых байта или символа, они могут быть * автоматически удалены* при извлечении их по индексу изShareableList
. Такое поведение.rstrip(b'\x00')
считается ошибкой и может быть устранено в будущем. См. gh-106939.Для приложений, где удаление завершающих нулей является проблемой, обходите ее, всегда безоговорочно добавляя дополнительный байт, отличный от 0, в конец таких значений при сохранении и безоговорочно удаляя его при извлечении:
>>> from multiprocessing import shared_memory >>> nul_bug_demo = shared_memory.ShareableList(['?\x00', b'\x03\x02\x01\x00\x00\x00']) >>> nul_bug_demo[0] '?' >>> nul_bug_demo[1] b'\x03\x02\x01' >>> nul_bug_demo.shm.unlink() >>> padded = shared_memory.ShareableList(['?\x00\x07', b'\x03\x02\x01\x00\x00\x00\x07']) >>> padded[0][:-1] '?\x00' >>> padded[1][:-1] b'\x03\x02\x01\x00\x00\x00' >>> padded.shm.unlink()
- count(value)¶
Возвращает количество вхождений значения value.
- index(value)¶
Возвращает первую позицию индекса value. Увеличьте значение
ValueError
, если value отсутствует.
- format¶
Доступный только для чтения атрибут, содержащий формат упаковки
struct
, используемый всеми текущими сохраненными значениями.
- shm¶
Экземпляр
SharedMemory
, в котором хранятся значения.
Следующий пример демонстрирует базовое использование экземпляра ShareableList
:
>>> from multiprocessing import shared_memory
>>> a = shared_memory.ShareableList(['howdy', b'HoWdY', -273.154, 100, None, True, 42])
>>> [ type(entry) for entry in a ]
[<class 'str'>, <class 'bytes'>, <class 'float'>, <class 'int'>, <class 'NoneType'>, <class 'bool'>, <class 'int'>]
>>> a[2]
-273.154
>>> a[2] = -78.5
>>> a[2]
-78.5
>>> a[2] = 'dry ice' # Changing data types is supported as well
>>> a[2]
'dry ice'
>>> a[2] = 'larger than previously allocated storage space'
Traceback (most recent call last):
...
ValueError: exceeds available storage for existing str
>>> a[2]
'dry ice'
>>> len(a)
7
>>> a.index(42)
6
>>> a.count(b'howdy')
0
>>> a.count(b'HoWdY')
1
>>> a.shm.close()
>>> a.shm.unlink()
>>> del a # Use of a ShareableList after call to unlink() is unsupported
В следующем примере показано, как один, два или несколько процессов могут получить доступ к одному и тому же ShareableList
, указав имя блока общей памяти, стоящего за ним:
>>> b = shared_memory.ShareableList(range(5)) # In a first process
>>> c = shared_memory.ShareableList(name=b.shm.name) # In a second process
>>> c
ShareableList([0, 1, 2, 3, 4], name='...')
>>> c[-1] = -999
>>> b[-1]
-999
>>> b.shm.close()
>>> c.shm.close()
>>> c.shm.unlink()
В следующих примерах показано, что объекты ShareableList
(и лежащие в их основе объекты SharedMemory
) могут быть выделены и отменены при необходимости. Обратите внимание, что это все равно будет тот же общий объект. Это происходит потому, что десериализованный объект имеет то же уникальное имя и просто присоединяется к существующему объекту с таким же именем (если объект все еще жив).:
>>> import pickle
>>> from multiprocessing import shared_memory
>>> sl = shared_memory.ShareableList(range(10))
>>> list(sl)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> deserialized_sl = pickle.loads(pickle.dumps(sl))
>>> list(deserialized_sl)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sl[0] = -1
>>> deserialized_sl[1] = -2
>>> list(sl)
[-1, -2, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(deserialized_sl)
[-1, -2, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sl.shm.close()
>>> sl.shm.unlink()
Python 3.11
Содержание
Дополнительно
Вы здесь:
-
Документация Django Python 3.11
- Стандартная библиотека Python
- Параллельное выполнение
multiprocessing.shared_memory
— Общая память для прямого доступа между процессами
- Параллельное выполнение
- Стандартная библиотека Python