TL; DR: Как разделить большой (200 МБ) файл только для чтения между несколькими процессами с высокой производительностью, к которому ОЧЕНЬ тяжело получить доступ, при этом каждый процесс не имеет полной копии в памяти.
РЕДАКТИРОВАТЬ: Это Похоже, если я просто передам словарь в качестве аргумента для многопроцессорной обработки. Пул / Процесс фактически не создаст копию, если работник не изменит словарь. Я просто предполагал, что это скопирует. Такое поведение, похоже, Unix только там, где доступен форк, и даже не всегда. Но если это так, это должно решить мою проблему, пока это не преобразуется в задание ETL.
Что я пытаюсь сделать:
У меня есть задача улучшить сценарий, который реплицирует данные из один магазин в другой. Нормализация и преобразование данных в пути. Эта задача работает в масштабе около 100 миллионов документов, поступающих из хранилища исходных документов, которые свернуты и отправлены в другое хранилище документов назначения.
Каждый документ имеет идентификатор, и существует еще одно хранилище документов, которое по сути является хранилище значений ключей этих идентификаторов сопоставлено с некоторой дополнительной информацией, необходимой для этой задачи. Это хранилище намного меньше и делает запросы к нему, пока идет документ из основного хранилища, на самом деле не вариант без тяжелого кеширования, и этот тяжелый кеш очень быстро становится копией всего этого. Я просто создаю словарь из всего этого магазина в начале, прежде чем что-то запускать, и использую его. Этот словарь имеет размер около 200 МБ. Обратите внимание, что этот словарь читается только из.
Для этого я настроил многопроцессорность и имею около 30 одновременных процессов. Я поделил работу для каждого процесса таким образом, чтобы каждый работал по разным показателям и мог выполнить все это примерно за 4 часа.
Я заметил, что я сильно привязан к процессору, выполняя следующие 2 вещи:
- Использование пула / потоков (что я сейчас делаю), чтобы каждый поток мог без проблем обращаться к dict. GIL убивает меня, и у меня один процесс работает на 100% все время, когда другие процессоры простаивают. Переключение на PyPy очень помогло, но я все еще не доволен этим подходом.
- Создание Multiprocessing.Manager (). Dict () для большого dict и обеспечение доступа дочерних процессов через него. Процесс сервера, создаваемый этим подходом, постоянно выполняется на 100%. Я не знаю почему, поскольку я только читаю из этого словаря, поэтому сомневаюсь, что это запирается. Я не знаю, как работает Менеджер внутри, но я предполагаю, что дочерние процессы соединяются через Pipes / Sockets для каждой выборки, и накладные расходы это огромные. Это также предполагает, что использование Reddis / Memcache будет иметь ту же проблему, если это правда. Может быть, его можно настроить лучше?
Я связан с памятью, когда выполняю следующие действия:
- Использование представления SharedMemory. Похоже, ты не можешь делать это для диктовок, как мне нужно. Я могу сериализовать dict, чтобы получить доступ к общему представлению, но для его использования в дочернем процессе вам нужно сериализовать данные в фактический пригодный для использования dict, который создает копию в процессе.
I Сильно подозреваю, что если я что-то пропустил, мне просто придется «скачать больше оперативной памяти» или переписать из Python во что-то без GIL (или использовать ETL, как это должно быть сделано в ...).
В случае с оперативной памятью, каков наиболее эффективный способ хранения диктанта, подобного этому, чтобы укусить его меньше? В настоящее время это стандартный dict, сопоставленный с кортежем дополнительной информации, состоящей из 3 long / float.
doc_to_docinfo = {"ID1": (5.2, 3.0, 455),}
Есть ли есть ли более эффективные реализации hashmap для этого варианта использования, чем то, что я делаю?