Объекты с общей памятью в многопроцессорной среде
=================================================

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

Если я использую многопроцессорную библиотеку, то этот гигантский массив будет многократно скопирован в разные процессы.

Есть ли способ позволить различным процессам использовать один и тот же массив? Этот объект массива доступен только для чтения и никогда не будет изменен.

Что сложнее, если arr не массив, а произвольный объект python, есть ли способ поделиться им?

[EDITED]

Я прочитал ответ, но я все еще немного сбит с толку. Поскольку fork () является копированием при записи, мы не должны вызывать никаких дополнительных затрат при порождении новых процессов в многопроцессорной библиотеке python. Но следующий код предполагает огромные накладные расходы:

Вывод (и, между прочим, стоимость увеличивается с увеличением размера массива, поэтому я подозреваю, что все еще есть издержки, связанные с копированием памяти):

```
construct array =  0.0178790092468
multiprocessing overhead =  0.252444982529

```

Почему такие огромные накладные расходы, если мы не копировали массив? И какую часть разделяемая память спасает меня?

Если вы используете операционную систему, которая использует копирование при записи`fork()` семантики (как и любой обычный unix), тогда, пока вы никогда не измените свою структуру данных, она будет доступна для всех дочерних процессов без использования дополнительной памяти. Вам не нужно будет делать ничего особенного (за исключением того, что вы абсолютно уверены, что не изменили объект).

**The most efficient thing you can do for your problem** было бы упаковать ваш массив в эффективную структуру массива (используя`numpy` или же[`array`](https://docs.python.org/library/array.html)), поместите это в общую память, оберните`multiprocessing.Array`и передайте это своим функциям.[Этот ответ показывает, как это сделать](https://stackoverflow.com/a/5550156/1002469).

Если вы хотитеwriteable разделяемый объект, тогда вам нужно будет обернуть его какой-то синхронизацией или блокировкой.`multiprocessing` обеспечивает[два способа сделать это](https://docs.python.org/library/multiprocessing.html#sharing-state-between-processes): использование общей памяти (подходит для простых значений, массивов или типов) или`Manager` прокси, где один процесс хранит память, а менеджер осуществляет арбитражный доступ к ней со стороны других процессов (даже по сети).

`Manager` Подход можно использовать с произвольными объектами Python, но он будет медленнее, чем эквивалент с использованием разделяемой памяти, поскольку объекты должны быть сериализованы / десериализованы и отправлены между процессами.

Есть[множество библиотек параллельной обработки и подходов, доступных в Python](https://wiki.python.org/moin/ParallelProcessing). `multiprocessing` Это отличная и хорошо округленная библиотека, но если у вас есть особые потребности, возможно, один из других подходов может быть лучше.



Это предполагаемый вариант использования для[луч](https://github.com/ray-project/ray), которая является библиотекой для параллельного и распределенного Python. Под капотом он сериализует объекты, используя[Apache Arrow](https://arrow.apache.org/) макет данных (формат с нулевой копией) и сохраняет их в[хранилище объектов с общей памятью](https://arrow.apache.org/docs/python/plasma.html) поэтому они могут быть доступны нескольким процессам без создания копий.

Код будет выглядеть следующим образом.

Если вы не звоните`ray.put` тогда массив все еще будет храниться в общей памяти, но это будет сделано один раз за вызов`func`что не то, что вы хотите.

Обратите внимание, что это будет работать не только для массивов, но и**also for objects that contain arrays**например, словари, отображающие целые числа в массивы, как показано ниже.

Вы можете сравнить производительность сериализации в Ray и pickle, выполнив следующее в IPython.

Сериализация с Ray только немного быстрее, чем pickle, но десериализация в 1000 раз быстрее из-за использования общей памяти (это число, конечно, будет зависеть от объекта).

Увидеть[Луч документации](https://ray.readthedocs.io/en/latest/?badge=latest), Вы можете прочитать больше о[быстрая сериализация с использованием Ray и Arrow](https://ray-project.github.io/2017/10/15/fast-python-serialization-with-ray-and-arrow.html), Заметьте, я один из разработчиков Ray.



Я столкнулся с той же проблемой и написал небольшой вспомогательный класс для совместной работы.

Я использую multiprocessing.RawArray (lockfree), а также доступ к массивам вообще не синхронизирован (lockfree), будьте осторожны, чтобы не выстрелить себе в ноги.

Благодаря решению я получаю ускорения примерно в 3 раза на четырехъядерном процессоре i7.

Вот код:
Не стесняйтесь использовать и улучшать его, и, пожалуйста, сообщайте о любых ошибках.