Ответ
Разделяемая память (shared memory) — это механизм межпроцессного взаимодействия (IPC), при котором несколько независимых процессов получают доступ к одному и тому же участку физической памяти. Это один из самых быстрых способов обмена данными, так как исключает затраты на копирование данных между процессами.
В Python, начиная с версии 3.8, для работы с разделяемой памятью используется модуль multiprocessing.shared_memory.
Ключевые шаги:
- Создание: Один процесс создает блок разделяемой памяти с помощью
shared_memory.SharedMemory(create=True, size=...). - Подключение: Другие процессы подключаются к этому блоку по его уникальному имени
shared_memory.SharedMemory(name=...). - Работа с данными: Данные записываются и читаются через буфер (
.buf), который представляет собойmemoryview. - Освобождение ресурсов: Каждый процесс должен закрыть свой экземпляр (
.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(), чтобы избежать утечек ресурсов в операционной системе.
Ответ 18+ 🔞
А, слушай, вот тебе про разделяемую память, это же просто пиздец какой удобный механизм, если процессы между собой общаться хотят быстро, без всей этой ебалы с очередями и сокетами. Представь, два процесса смотрят на один и тот же кусок оперативки, как два мужика на одну бутылку. Данные туда-сюда — и копировать ничего не надо, скорость — овердохуища.
В Питоне, с версии 3.8, для этого есть модуль multiprocessing.shared_memory. Главное — не накосячить с порядком действий, а то будет как в том анекдоте про Герасима, только вместо Муму — утечка памяти на весь комп.
Как это, блядь, работает:
- Создаёшь: Один процесс, обычно главный, кричит системе: «Дай мне вот столько байт!» через
shared_memory.SharedMemory(create=True, size=...). Система выделяет и выдаёт уникальное имя, типаpsm_5f4b1. - Цепляешься: Другие процессы, как пидары на халяву, подключаются к этому же блоку по этому самому имени:
shared_memory.SharedMemory(name=...). - Работаешь: Все лезут в один буфер (
.buf), который ведёт себя какmemoryview. Пишешь туда байты, читаешь оттуда — красота. - Убираешь за собой: Это самое главное, ёпта! Каждый процесс должен вызвать
.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("Писака: подключился к памяти.")
# Пишем 'Hello' в первые 5 байт
message = b'Hello'
existing_shm.buf[:len(message)] = message
print("Писака: записал данные.")
# Закрываем свой доступ
existing_shm.close()
def reader(shm_name):
time.sleep(1) # Ждём чутка, пока писака своё дело сделает
# Тоже цепляемся
existing_shm = shared_memory.SharedMemory(name=shm_name)
print("Читака: подключился к памяти.")
# Читаем первые 5 байт
read_message = bytes(existing_shm.buf[:5])
print(f"Читака: прочитал данные - {read_message.decode()}")
existing_shm.close()
if __name__ == "__main__":
# 1. Главный создаёт блок памяти, скажем, на 10 байт
shm = shared_memory.SharedMemory(create=True, size=10)
print(f"Главный: создал блок памяти с именем '{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("Главный: память освобождена.")
А теперь, внимание, важные моменты, где все обычно ебутся:
- Синхронизация — твоя забота. Сама по себе разделяемая память синхронизацию не обеспечивает. Если два процесса начнут писать в одно место одновременно, будет race condition, пиздец и каша. Нужно использовать
LockилиSemaphoreиз того жеmultiprocessing, чтобы доступ был по очереди, как в нормальной бане. - Жизненный цикл. Если забыть
unlink(), блок памяти останется в системе. Это как оставить после вечеринки пустые бутылки — операционка тебя не похвалит. Утечки, блядь.