Как легко хранить удобные для чтения на python структуры данных только для чтения в общей памяти

У меня есть процесс python, служащий сервером WSGI-apache. У меня много копий этого процесса, запущенного на каждой из нескольких машин. Около 200 мегабайт моего процесса - это данные python, доступные только для чтения. Я хотел бы разместить эти данные в сегменте с отображением памяти, чтобы процессы могли совместно использовать одну копию этих данных. Лучше всего было бы прикрепить эти данные, чтобы они могли быть реальными объектами данных python 2.7, а не разбирать их из чего-то вроде pickle или DBM или SQLite.

Есть ли у кого-нибудь образец кода или указателей на проект, который сделал это, чтобы поделиться?

Ответ 1

Этот пост от @modelnine на StackOverflow дает действительно большой исчерпывающий ответ на этот вопрос. Как он упомянул, использование потоков, а не процессирование на вашем веб-сервере может значительно усугубить влияние этого. я столкнулась с аналогичной проблемой, пытающейся совместно использовать чрезвычайно большие массивы NumPy между процессами CLI Python, использующими некоторый тип разделяемой памяти пару лет назад, и мы закончили тем, что использовали сочетание sharedmem Расширение Python для обмена данными между рабочими (которые в некоторых случаях доказали утечку памяти, но, вероятно, это исправление). Для вас может работать только метод только для чтения mmap(), но я не уверен, как это сделать в pure-python (NumPy имеет метод memmapping, описанный здесь), Я никогда не нашел ясных и простых ответов на этот вопрос, но, надеюсь, это может указывать на некоторые новые направления. Сообщите нам, что вы делаете!

Ответ 2

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

Если проблемы с памятью являются проблемой, вы можете взглянуть на использование multiprocessing.Value или multiprocessing.Array без блокировок для этого: https://docs.python.org/2/library/multiprocessing.html#shared-ctypes-objects

Кроме этого вам придется полагаться на внешний процесс и некоторые сериализации, чтобы это сделать, я бы посмотрел на Redis или Memcached, если бы я был вами.

Ответ 3

Одна из возможностей - создать C- или С++-расширение, которое предоставляет интерфейс Pythonic для ваших общих данных. Вы можете использовать карту памяти 200 МБ необработанных данных, а затем предоставить C-или С++-расширение для WSGI-сервиса. То есть вы могли бы иметь обычные (не разделенные) объекты python, реализованные на C, которые извлекают данные из какого-то двоичного формата в разделяемой памяти. Я знаю, что это не совсем то, что вы хотели, но таким образом данные, по крайней мере, выглядели бы pythonic для WSGI-приложения.

Однако, если ваши данные состоят из множества очень маленьких объектов, тогда становится важным, чтобы даже "точки входа" находились в общей памяти (иначе они будут тратить слишком много памяти). То есть, вы должны убедиться, что указатели PyObject *, которые составляют интерфейс к вашим данным, фактически сами указывают на общую память. I.e, сами объекты python должны быть в общей памяти. Насколько я могу читать официальные документы, это не поддерживается. Тем не менее, вы всегда можете попробовать "создавать" объекты python в общей памяти и посмотреть, работает ли он. Я предполагаю, что это сработает, пока интерпретатор Python не попытается освободить память. Но в вашем случае это не будет, поскольку это долговечно и доступно только для чтения.

Ответ 4

Сложно обмениваться реальными объектами python, поскольку они связаны с адресным пространством процесса. Однако, если вы используете mmap, вы можете создать очень полезные общие объекты. Я бы создал один процесс для предварительной загрузки данных, а остальные могли бы использовать его. Я нашел неплохую запись в блоге, в которой описывается, как это можно сделать: http://blog.schmichael.com/2011/05/15/sharing-python-data-between-processes-using-mmap/