Что такое разделяемая память (shared memory) и как ее использовать в Python

Ответ

Разделяемая память (shared memory) — это механизм межпроцессного взаимодействия (IPC), при котором несколько независимых процессов получают доступ к одному и тому же участку физической памяти. Это один из самых быстрых способов обмена данными, так как исключает затраты на копирование данных между процессами.

В Python, начиная с версии 3.8, для работы с разделяемой памятью используется модуль multiprocessing.shared_memory.

Ключевые шаги:

  1. Создание: Один процесс создает блок разделяемой памяти с помощью shared_memory.SharedMemory(create=True, size=...).
  2. Подключение: Другие процессы подключаются к этому блоку по его уникальному имени shared_memory.SharedMemory(name=...).
  3. Работа с данными: Данные записываются и читаются через буфер (.buf), который представляет собой memoryview.
  4. Освобождение ресурсов: Каждый процесс должен закрыть свой экземпляр (.close()), а создавший процесс — дополнительно удалить блок из системы (.unlink()).

Пример: один процесс пишет, другой читает

import multiprocessing as mp
from multiprocessing import shared_memory
import time

def writer(shm_name):
    # Подключаемся к существующей памяти
    existing_shm = shared_memory.SharedMemory(name=shm_name)
    print("Writer: подключился к памяти.")
    # Записываем данные в первые 5 байт
    message = b'Hello'
    existing_shm.buf[:len(message)] = message
    print("Writer: записал данные.")
    # Закрываем доступ
    existing_shm.close()

def reader(shm_name):
    time.sleep(1) # Ждем, пока writer запишет данные
    # Подключаемся к существующей памяти
    existing_shm = shared_memory.SharedMemory(name=shm_name)
    print("Reader: подключился к памяти.")
    # Читаем первые 5 байт
    read_message = bytes(existing_shm.buf[:5])
    print(f"Reader: прочитал данные - {read_message.decode()}")
    existing_shm.close()

if __name__ == "__main__":
    # 1. Создаем блок разделяемой памяти
    shm = shared_memory.SharedMemory(create=True, size=10)
    print(f"Main: создал блок памяти с именем '{shm.name}'")

    # 2. Запускаем процессы
    p_writer = mp.Process(target=writer, args=(shm.name,))
    p_reader = mp.Process(target=reader, args=(shm.name,))

    p_writer.start()
    p_reader.start()

    p_writer.join()
    p_reader.join()

    # 3. Освобождаем и удаляем ресурсы
    shm.close()
    shm.unlink()
    print("Main: память освобождена.")

Важные аспекты:

  • Синхронизация: Разделяемая память не обеспечивает синхронизацию. Для предотвращения гонки данных (race conditions) необходимо использовать примитивы синхронизации, такие как multiprocessing.Lock или Semaphore.
  • Управление жизненным циклом: Крайне важно корректно вызывать close() и unlink(), чтобы избежать утечек ресурсов в операционной системе.