Я работаю над расширением Python, которое выполняет некоторые специализированные древовидные операции с большой (5 ГБ +) структурой данных в памяти.
Базовая структура данных уже поточнобезопасна (она использует блокировки RW), и я написал обертку вокруг нее, которая выставляет ее на python. Он поддерживает несколько читателей одновременно, только один писатель, и я использую pthread_rwlock
для синхронизации доступа. Поскольку приложение очень тяжело для чтения, несколько читателей должны обеспечить приличное улучшение производительности (я надеюсь).
Тем не менее, я не могу определить, каково правильное решение, чтобы позволить хранилищу данных расширения быть доступным для нескольких процессов Python, доступных через multiprocessing
модуль.
В принципе, я хотел бы что-то похожее на текущий multiprocessing.Value
/multiprocessing.Array
система, но оговорка здесь заключается в том, что мое расширение выделяет всю свою собственную память в C ++.
Как я могу позволить нескольким процессам получить доступ к моей общей структуре данных?
Источники Вот (Библиотека C ++ только для заголовков) и Вот (Обертка Cython).
Прямо сейчас, если я создаю экземпляр дерева, а затем передаю ссылки нескольким процессам, происходит сбой с ошибкой сериализации:
Traceback (most recent call last):
File "/usr/lib/python3.4/multiprocessing/queues.py", line 242, in _feed
obj = ForkingPickler.dumps(obj)
File "/usr/lib/python3.4/multiprocessing/reduction.py", line 50, in dumps
cls(buf, protocol).dump(obj)
TypeError: cannot serialize '_io.TextIOWrapper' object
В настоящее время я выпускаю GIL в своей библиотеке, но есть некоторые будущие задачи, которые могли бы значительно выиграть от независимых процессов, и я хотел бы избежать необходимости внедрения системы RPC для связи с деревом BK.
Если данные расширения будут существовать как единый логический изменяемый объект для нескольких процессов (поэтому изменение в процессе A будет отражено в представлении в процессе B), вы не можете избежать какого-то механизма IPC. Пространства памяти двух процессов разделены; Python не может волшебным образом делиться неразделенными данными.
Самое близкое, что вы можете получить (без явного использования разделяемой памяти на уровне C, которую можно использовать для сопоставления одной и той же памяти в каждом процессе), — это использовать собственный подкласс: multiprocessing.BaseManager
, который просто скрыл бы IPC от вас (фактический объект жил бы в единственном процессе с другими процессами, проксирующими к тому оригинальному объекту). Ты можешь видеть действительно простой пример в multiprocessing
документы.
Подход менеджера прост, но с точки зрения производительности он, вероятно, не будет таким горячим; Совместно используемая память на уровне C позволяет избежать накладных расходов, которых не может избежать механизм проксирования. Вам нужно проверить, чтобы проверить что-нибудь. Насколько мне известно, использование в C ++ STL разделяемой памяти было бы огромной болью, и, вероятно, это не стоило бы усилий, поэтому, если не показалось, что подход менеджера слишком медленный, я бы даже не пытался оптимизировать.
Других решений пока нет …