multiprocessing.shared_memory.md
1> **Источник:** https://python-all.ru/3.9/library/multiprocessing.shared_memory.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`multiprocessing.shared_memory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#module-multiprocessing.shared_memory) – Предоставляет разделяемую память для прямого доступа между процессами89**Исходный код:** [Lib/multiprocessing/shared\_memory.py](https://python-all.ru/src/3.9/Lib/multiprocessing/shared_memory.py)1011Новое в версии 3.8.1213---1415Этот модуль предоставляет класс [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory) для выделения и управления разделяемой памятью, к которой могут обращаться один или несколько процессов на многоядерной или симметричной мультипроцессорной (SMP) машине. Для упрощения управления жизненным циклом разделяемой памяти, особенно между разными процессами, в модуле `multiprocessing.managers` также предоставляется подкласс [`BaseManager`](https://python-all.ru/3.9/library/multiprocessing.html#multiprocessing.managers.BaseManager) – `SharedMemoryManager`.1617В этом модуле разделяемая память означает блоки разделяемой памяти «в стиле System V» (хотя реализация не обязательно буквально такая) и не относится к «распределённой разделяемой памяти». Такой стиль разделяемой памяти позволяет разным процессам читать и писать в общую (или разделяемую) область оперативной памяти. Обычно процессы ограничены доступом только к своему собственному адресному пространству, но разделяемая память позволяет обмениваться данными между процессами, избегая необходимости отправлять сообщения между процессами, содержащие эти данные. Прямое разделение данных через память может дать значительный выигрыш в производительности по сравнению с передачей данных через диск, сокет или другие механизмы, требующие сериализации/десериализации и копирования данных.1819#### `class multiprocessing.shared_memory.SharedMemory(name=None, create=False, size=0)`2021Создаёт новый блок разделяемой памяти или подключается к существующему блоку разделяемой памяти. Каждому блоку разделяемой памяти присваивается уникальное имя. Таким образом, один процесс может создать блок разделяемой памяти с определённым именем, а другой процесс может подключиться к тому же блоку разделяемой памяти, используя то же имя.2223Будучи ресурсом для обмена данными между процессами, блоки разделяемой памяти могут пережить породивший их процесс. Когда процесс больше не нуждается в доступе к блоку разделяемой памяти, который может по-прежнему требоваться другим процессам, следует вызвать метод [`close()`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.close). Когда блок разделяемой памяти больше не нужен ни одному процессу, для надлежащей очистки следует вызвать метод [`unlink()`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.unlink).2425*name* – это уникальное имя для запрашиваемой разделяемой памяти, задаваемое строкой. При создании нового блока разделяемой памяти, если в качестве имени указано `None` (значение по умолчанию), будет сгенерировано новое имя.2627*create* управляет тем, создаётся ли новый блок разделяемой памяти (`True`) или подключается существующий блок разделяемой памяти (`False`).2829*size* задаёт запрашиваемое количество байт при создании нового блока разделяемой памяти. Поскольку некоторые платформы выделяют память блоками в соответствии с размером страницы памяти, фактический размер блока разделяемой памяти может быть больше или равен запрошенному. При подключении к существующему блоку разделяемой памяти параметр `size` игнорируется.3031#### `close()`3233Закрывает доступ к разделяемой памяти из данного экземпляра. Для обеспечения правильной очистки ресурсов каждый экземпляр должен вызвать `close()`, когда он больше не нужен. Обратите внимание: вызов `close()` не приводит к уничтожению самого блока разделяемой памяти.3435#### `unlink()`3637Запрашивает уничтожение нижележащего блока разделяемой памяти. Для обеспечения правильной очистки ресурсов `unlink()` должен быть вызван один раз (и только один раз) во всех процессах, которым нужен этот блок разделяемой памяти. После запроса на уничтожение блок разделяемой памяти может быть уничтожен немедленно или не сразу, и это поведение может различаться на разных платформах. Попытки доступа к данным внутри блока разделяемой памяти после вызова `unlink()` могут привести к ошибкам доступа к памяти. Примечание: последний процесс, освобождающий блок разделяемой памяти, может вызывать `unlink()` и [`close()`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.close) в любом порядке.3839#### `buf`4041Представление памяти (memoryview) содержимого блока разделяемой памяти.4243#### `name`4445Доступ только для чтения к уникальному имени блока разделяемой памяти.4647#### `size`4849Доступ только для чтения к размеру блока разделяемой памяти в байтах.5051В следующем примере демонстрируется низкоуровневое использование экземпляров [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory):5253```python54>>> from multiprocessing import shared_memory55>>> shm_a = shared_memory.SharedMemory(create=True, size=10)56>>> type(shm_a.buf)57<class 'memoryview'>58>>> buffer = shm_a.buf59>>> len(buffer)601061>>> buffer[:4] = bytearray([22, 33, 44, 55]) # Изменить несколько за раз62>>> buffer[4] = 100 # Изменить один байт за раз63>>> # Подключиться к существующему блоку разделяемой памяти64>>> shm_b = shared_memory.SharedMemory(shm_a.name)65>>> import array66>>> array.array('b', shm_b.buf[:5]) # Скопировать данные в новый array.array67array('b', [22, 33, 44, 55, 100])68>>> shm_b.buf[:5] = b'howdy' # Изменить через shm_b, используя bytes69>>> bytes(shm_a.buf[:5]) # Доступ через shm_a70b'howdy'71>>> shm_b.close() # Закрыть каждый экземпляр SharedMemory72>>> shm_a.close()73>>> shm_a.unlink() # Вызвать unlink только один раз, чтобы освободить разделяемую память74```7576В следующем примере демонстрируется практическое применение класса [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory) с [массивами NumPy](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html) – доступ к одному и тому же `numpy.ndarray` из двух разных оболочек Python:7778```pycon79>>> # В первой интерактивной оболочке Python80>>> import numpy as np81>>> a = np.array([1, 1, 2, 3, 5, 8]) # Начать с существующего массива NumPy82>>> from multiprocessing import shared_memory83>>> shm = shared_memory.SharedMemory(create=True, size=a.nbytes)84>>> # Теперь создать массив NumPy, поддерживаемый разделяемой памятью85>>> b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)86>>> b[:] = a[:] # Скопировать исходные данные в разделяемую память87>>> b88array([1, 1, 2, 3, 5, 8])89>>> type(b)90<class 'numpy.ndarray'>91>>> type(a)92<class 'numpy.ndarray'>93>>> shm.name # Мы не указали имя, поэтому оно было выбрано автоматически94'psm_21467_46075'9596>>> # В той же оболочке или в новой оболочке Python на той же машине97>>> import numpy as np98>>> from multiprocessing import shared_memory99>>> # Подключиться к существующему блоку разделяемой памяти100>>> existing_shm = shared_memory.SharedMemory(name='psm_21467_46075')101>>> # Обратите внимание, что a.shape равно (6,), а a.dtype равно np.int64 в этом примере102>>> c = np.ndarray((6,), dtype=np.int64, buffer=existing_shm.buf)103>>> c104array([1, 1, 2, 3, 5, 8])105>>> c[-1] = 888106>>> c107array([ 1, 1, 2, 3, 5, 888])108109>>> # Вернувшись в первую интерактивную оболочку Python, b отражает это изменение110>>> b111array([ 1, 1, 2, 3, 5, 888])112113>>> # Очистка из второй оболочки Python114>>> del c # Необязательно; просто подчёркивается, что массив больше не используется115>>> existing_shm.close()116117>>> # Очистка из первой оболочки Python118>>> del b # Необязательно; просто подчёркивается, что массив больше не используется119>>> shm.close()120>>> shm.unlink() # Освободить и удалить блок разделяемой памяти в самом конце121```122123#### `class multiprocessing.managers.SharedMemoryManager([address[, authkey]])`124125Подкласс [`BaseManager`](https://python-all.ru/3.9/library/multiprocessing.html#multiprocessing.managers.BaseManager), который можно использовать для управления блоками разделяемой памяти между процессами.126127Вызов [`start()`](https://python-all.ru/3.9/library/multiprocessing.html#multiprocessing.managers.BaseManager.start) у экземпляра [`SharedMemoryManager`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager) запускает новый процесс. Единственная цель этого нового процесса – управлять жизненным циклом всех блоков разделяемой памяти, созданных через него. Чтобы запустить освобождение всех блоков разделяемой памяти, управляемых этим процессом, вызовите [`shutdown()`](https://python-all.ru/3.9/library/multiprocessing.html#multiprocessing.managers.BaseManager.shutdown) у экземпляра. Это вызовет `SharedMemory.unlink()` для всех объектов [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager.SharedMemory), управляемых этим процессом, а затем остановит сам процесс. Создавая экземпляры `SharedMemory` через `SharedMemoryManager`, мы избегаем необходимости вручную отслеживать и инициировать освобождение ресурсов разделяемой памяти.128129Этот класс предоставляет методы для создания и возврата экземпляров [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager.SharedMemory), а также для создания объекта, подобного списку ([`ShareableList`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager.ShareableList)), основанного на разделяемой памяти.130131Обратитесь к [`multiprocessing.managers.BaseManager`](https://python-all.ru/3.9/library/multiprocessing.html#multiprocessing.managers.BaseManager) за описанием унаследованных необязательных входных аргументов *address* и *authkey*, а также за тем, как их можно использовать для подключения к существующей службе `SharedMemoryManager` из других процессов.132133#### `SharedMemory(size)`134135Создаёт и возвращает новый объект [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager.SharedMemory) с указанным `size` в байтах.136137#### `ShareableList(sequence)`138139Создаёт и возвращает новый объект [`ShareableList`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.managers.SharedMemoryManager.ShareableList), инициализированный значениями из входного `sequence`.140141Следующий пример демонстрирует основные механизмы `SharedMemoryManager`:142143```pycon144>>> from multiprocessing.managers import SharedMemoryManager145>>> smm = SharedMemoryManager()146>>> smm.start() # Запуск процесса, управляющего блоками разделяемой памяти147>>> sl = smm.ShareableList(range(4))148>>> sl149ShareableList([0, 1, 2, 3], name='psm_6572_7512')150>>> raw_shm = smm.SharedMemory(size=128)151>>> another_sl = smm.ShareableList('alpha')152>>> another_sl153ShareableList(['a', 'l', 'p', 'h', 'a'], name='psm_6572_12221')154>>> smm.shutdown() # Вызывает unlink() для sl, raw_shm и another_sl155```156157Следующий пример демонстрирует потенциально более удобный шаблон использования объектов `SharedMemoryManager` через оператор [`with`](https://python-all.ru/3.9/reference/compound_stmts.html#with), чтобы гарантировать освобождение всех блоков разделяемой памяти после того, как они больше не нужны:158159```pycon160>>> with SharedMemoryManager() as smm:161... sl = smm.ShareableList(range(2000))162... # Разделение работы между двумя процессами, сохранение частичных результатов в sl163... p1 = Process(target=do_work, args=(sl, 0, 1000))164... p2 = Process(target=do_work, args=(sl, 1000, 2000))165... p1.start()166... p2.start() # multiprocessing.Pool может быть эффективнее167... p1.join()168... p2.join() # Ожидание завершения всей работы в обоих процессах169... total_result = sum(sl) # Объединение частичных результатов из sl170```171172При использовании `SharedMemoryManager` в операторе [`with`](https://python-all.ru/3.9/reference/compound_stmts.html#with) все блоки разделяемой памяти, созданные с помощью этого менеджера, освобождаются при завершении выполнения блока кода оператора [`with`](https://python-all.ru/3.9/reference/compound_stmts.html#with).173174#### `class multiprocessing.shared_memory.ShareableList(sequence=None, *, name=None)`175176Предоставляет изменяемый объект, подобный списку, где все хранящиеся значения хранятся в блоке разделяемой памяти. Это ограничивает сохраняемые значения только встроенными типами данных `int`, `float`, `bool`, `str` (менее 10 МБ каждый), `bytes` (менее 10 МБ каждый) и `None`. Он также существенно отличается от встроенного типа `list` тем, что эти списки не могут изменять свою общую длину (т.е. нет append, insert и т.д.) и не поддерживают динамическое создание новых экземпляров [`ShareableList`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList) через срезы.177178*sequence* используется для заполнения нового `ShareableList` значениями. Установите в `None`, чтобы вместо этого подключиться к уже существующему `ShareableList` по его уникальному имени разделяемой памяти.179180*name* – это уникальное имя для запрашиваемой разделяемой памяти, как описано в определении [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory). При подключении к существующему `ShareableList` укажите уникальное имя его блока разделяемой памяти, оставив `sequence` равным `None`.181182#### `count(value)`183184Возвращает количество вхождений `value`.185186#### `index(value)`187188Возвращает индекс первого вхождения `value`. Возбуждает [`ValueError`](https://python-all.ru/3.9/library/exceptions.html#ValueError), если `value` отсутствует.189190#### `format`191192Атрибут только для чтения, содержащий формат упаковки [`struct`](https://python-all.ru/3.9/library/struct.html#module-struct), используемый всеми текущими хранимыми значениями.193194#### `shm`195196Экземпляр [`SharedMemory`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory), в котором хранятся значения.197198Следующий пример демонстрирует базовое использование экземпляра [`ShareableList`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList):199200```python201>>> from multiprocessing import shared_memory202>>> a = shared_memory.ShareableList(['howdy', b'HoWdY', -273.154, 100, None, True, 42])203>>> [ type(entry) for entry in a ]204[<class 'str'>, <class 'bytes'>, <class 'float'>, <class 'int'>, <class 'NoneType'>, <class 'bool'>, <class 'int'>]205>>> a[2]206-273.154207>>> a[2] = -78.5208>>> a[2]209-78.5210>>> a[2] = 'dry ice' # Изменение типов данных также поддерживается211>>> a[2]212'dry ice'213>>> a[2] = 'larger than previously allocated storage space'214Traceback (most recent call last):215 ...216ValueError: exceeds available storage for existing str217>>> a[2]218'dry ice'219>>> len(a)2207221>>> a.index(42)2226223>>> a.count(b'howdy')2240225>>> a.count(b'HoWdY')2261227>>> a.shm.close()228>>> a.shm.unlink()229>>> del a # Использование ShareableList после вызова unlink() не поддерживается230```231232Следующий пример показывает, как один, два или много процессов могут получить доступ к одному и тому же [`ShareableList`](https://python-all.ru/3.9/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList), указав имя лежащего в его основе блока разделяемой памяти:233234```python235>>> b = shared_memory.ShareableList(range(5)) # В первом процессе236>>> c = shared_memory.ShareableList(name=b.shm.name) # Во втором процессе237>>> c238ShareableList([0, 1, 2, 3, 4], name='...')239>>> c[-1] = -999240>>> b[-1]241-999242>>> b.shm.close()243>>> c.shm.close()244>>> c.shm.unlink()245```246