Почему список не меняется при запуске Process в Python

Почему список не меняется при запуске Process в Python

@python_quiz

Разберем этот квиз

Код квиза:

python

Кратко: родительский список останется пустым. Ни исключения, ни зависания — просто 0. Ниже объясню почему, какие варианты поведения ожидать и как правильно передавать разделяемые данные между процессами.

Что происходит (интуитивно)

  • multiprocessing запускает отдельный процесс (дочерний). Процессы в ОС имеют свою виртуальную память — они не разделяют объекты Python напрямую.
  • При создании дочернего процесса аргументы обычно сериализуются (pickling) и передаются дочернему процессу (на Windows это явно spawn). На Unix часто используется fork, но это лишь копирование адресного пространства (copy-on-write): после изменения в дочернем процессе изменения не попадут в память родителя.
  • В итоге дочерний процесс получает свою копию списка и добавляет элемент в неё. Родительский x остаётся без изменений, поэтому len(x) == 0.

Почему не будет исключения и не произойдет зависание

  • Список является picklable, поэтому передача аргумента не вызовет ошибки.
  • worker завершается нормально, join дождётся завершения, поэтому зависания нет.

Демонстрация ожидаемого вывода

Ожидаемый результат выполнения исходного кода:

text

Способы правильно делиться данными между процессами

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

1) multiprocessing.Manager().list()

python

Плюс: просто в использовании. Минус: медленнее обычных структур, т.к. доступ идёт через менеджер и сериализацию.

2) Queue (для передачи сообщений/результатов)

python

Queue хороша для передачи событий, результатов или потоков данных.

3) multiprocessing.Array / Value (разделяемая память с фиксированным типом)

python

Полезно для простых числовых наборов. Array обеспечивает низкоуровневый совместный доступ.

4) shared_memory (Python 3.8+) — для NumPy и больших буферов

python

Подходит для высокопроизводительного обмена большими массивами (особенно с NumPy).

Советы и подводные камни

  • На Windows используется spawn, поэтому передача параметров всегда подразумевает сериализацию. На Unix по умолчанию fork, но изменения в дочернем процессе всё равно не видны родителю.
  • Пользуйтесь менеджерами или очередями для упрощённого обмена, если не нужна сверхвысокая производительность.
  • Для числовых массивов и больших данных предпочтителен shared_memory или Array.
  • Не забывайте закрывать/освобождать ресурсы shared_memory и Manager.

Вывод

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

Report Page