Дочерние процессы порождены через многопроцессорные общие объекты, созданные ранее в программе?
У меня следующая установка:
do_some_processing(filename):
for line in file(filename):
if line.split(',')[0] in big_lookup_object:
# something here
if __name__ == '__main__':
big_lookup_object = marshal.load('file.bin')
pool = Pool(processes=4)
print pool.map(do_some_processing, glob.glob('*.data'))
Я загружаю в память какой-то большой объект, а затем создаю пул рабочих, которым необходимо использовать этот большой объект. Доступ к большому объекту доступен только для чтения, мне не нужно передавать его изменения между процессами.
Мой вопрос: загружается ли большой объект в общую память, как если бы я создал процесс в unix / c, или каждый процесс загружает свою собственную копию большого объекта?
Обновление: чтобы уточнить - big_lookup_object - это общий поисковый объект. Мне не нужно разбивать это на части и обрабатывать отдельно. Мне нужно сохранить единственную его копию. Работа, которую мне нужно разделить, - это чтение множества других больших файлов и поиск элементов в этих больших файлах по объекту поиска.
Дальнейшее обновление: база данных - прекрасное решение, memcached может быть лучшим решением, а файл на диске (полка или dbm) может быть еще лучше. В этом вопросе меня особенно интересовало решение в памяти. В качестве окончательного решения я буду использовать hadoop, но я хотел посмотреть, могу ли я также иметь локальную версию в памяти.
источник
marshal.load
родительский и для каждого дочернего (каждый процесс импортирует модуль).Ответы:
"Дочерние процессы порождены через многопроцессорные общие объекты, созданные ранее в программе?"
Нет (python до 3.8) и Да в 3.8 ( https://docs.python.org/3/library/multiprocessing.shared_memory.html#module-multiprocessing.shared_memory )
Процессы имеют независимое пространство памяти.
Решение 1
Сделайте это, чтобы наилучшим образом использовать большую структуру с большим количеством рабочих.
Запишите каждого рабочего как «фильтр» - считывает промежуточные результаты из стандартного ввода, выполняет работу, записывает промежуточные результаты в стандартный вывод.
Подключите всех воркеров в конвейер:
Каждый процесс читает, работает и пишет.
Это замечательно эффективно, поскольку все процессы выполняются одновременно. Записи и чтения проходят напрямую через общие буферы между процессами.
Решение 2
В некоторых случаях у вас более сложная структура - часто «разветвленная» структура. В этом случае у вас есть родитель с несколькими детьми.
Родитель открывает исходные данные. Родитель разветвляет несколько детей.
Родитель читает исходный код, передает части источника каждому параллельно запущенному дочернему элементу.
Когда родитель дойдет до конца, закройте трубу. Ребенок получает конец файла и заканчивает нормально.
Дочерние части приятно писать, потому что каждый ребенок просто читает
sys.stdin
.У родителя есть немного причудливой работы по созданию всех потомков и правильному удержанию труб, но это не так уж плохо.
Фан-ин - это противоположная структура. Ряду независимо выполняющихся процессов необходимо чередовать свои входные данные в общий процесс. Коллектор не так просто написать, так как он должен читать из множества источников.
Чтение из многих именованных каналов часто выполняется с помощью
select
модуля, чтобы увидеть, какие каналы имеют ожидающий ввод.Решение 3
Общий поиск - это определение базы данных.
Решение 3А - загрузить базу данных. Позвольте рабочим обработать данные в базе данных.
Решение 3B - создайте очень простой сервер, используя werkzeug (или аналогичный), чтобы предоставить приложениям WSGI, которые отвечают на HTTP GET, чтобы рабочие могли запрашивать сервер.
Решение 4
Объект общей файловой системы. ОС Unix предлагает объекты разделяемой памяти. Это просто файлы, которые отображаются в памяти, так что ввод-вывод подкачки выполняется вместо операций чтения с буферизацией по соглашению.
Вы можете сделать это из контекста Python несколькими способами.
Напишите программу запуска, которая (1) разбивает исходный гигантский объект на более мелкие объекты и (2) запускает рабочие процессы, каждый с меньшим объектом. Меньшие объекты могут быть обработаны объектами Python, чтобы сэкономить немного времени на чтение файла.
Напишите программу запуска, которая (1) считывает ваш исходный гигантский объект и записывает файл со структурой страниц и байтовым кодом, используя
seek
операции, чтобы гарантировать, что отдельные разделы легко найти с помощью простых поисков. Это то, что делает ядро базы данных - разбивает данные на страницы, упрощает поиск каждой страницы с помощью файлаseek
.Создавать воркеры с доступом к этому большому файлу со структурой страниц. Каждый рабочий может искать нужные части и выполнять там свою работу.
источник
Дочерние процессы порождены через многопроцессорные общие объекты, созданные ранее в программе?
Это зависит. Для глобальных переменных, доступных только для чтения, это часто можно считать так (помимо потребляемой памяти), иначе этого не должно быть.
документация multiprocessing говорит:
Better to inherit than pickle/unpickle
Explicitly pass resources to child processes
Global variables
пример
В Windows (один процессор):
С
sleep
:Без
sleep
:источник
z
никто не поделился. Таким образом, это отвечает на вопрос: «Нет, по крайней мере, в Windows родительская переменная не используется совместно между дочерними элементами».z
случая), они могут считаться общими.С.Лотт прав. Комбинации клавиш для многопроцессорной обработки в Python фактически предоставляют вам отдельный дублированный фрагмент памяти.
В большинстве систем * nix использование вызова нижнего уровня на
os.fork()
самом деле даст вам память для копирования при записи, о чем вы можете подумать. AFAIK, теоретически, в самой упрощенной из возможных программ, вы могли бы читать из этих данных, не дублируя их.Однако в интерпретаторе Python все не так просто. Данные объекта и метаданные хранятся в одном и том же сегменте памяти, поэтому даже если объект никогда не изменяется, что-то вроде счетчика ссылок для этого объекта, который увеличивается, вызовет запись в память и, следовательно, копию. Практически любая программа Python, которая делает больше, чем «print 'hello», вызовет приращение счетчика ссылок, так что вы, вероятно, никогда не поймете преимущества копирования при записи.
Даже если бы кому-то удалось взломать решение с общей памятью в Python, попытка координировать сбор мусора между процессами, вероятно, была бы довольно болезненной.
источник
Если вы работаете под Unix, они могут совместно использовать один и тот же объект из-за того, как работает fork (т. Е. У дочерних процессов есть отдельная память, но она копируется при записи, поэтому она может совместно использоваться, пока ее никто не изменяет). Я пробовал следующее:
и получил следующий результат:
Конечно, это не доказывает, что копия не была сделана, но вы должны иметь возможность проверить это в своей ситуации, посмотрев на вывод,
ps
чтобы увидеть, сколько реальной памяти использует каждый подпроцесс.источник
У разных процессов разное адресное пространство. Как запускать разные экземпляры интерпретатора. Вот для чего нужен IPC (межпроцессное взаимодействие).
Для этого можно использовать очереди или каналы. Вы также можете использовать rpc поверх tcp, если хотите распределить процессы по сети позже.
http://docs.python.org/dev/library/multiprocessing.html#exchanging-objects-between-processes
источник
Не имеет прямого отношения к многопроцессорности как таковой, но из вашего примера может показаться, что вы можете просто использовать модуль полки или что-то в этом роде. Неужели "big_lookup_object" действительно должен быть полностью в памяти?
источник
Нет, но вы можете загрузить свои данные как дочерний процесс и разрешить ему делиться своими данными с другими дочерними процессами. увидеть ниже.
источник
Для платформы Linux / Unix / MacOS forkmap - быстрое и грязное решение.
источник