Python: Почему многопроцессорная блокировка здесь используется совместно?

Я пытаюсь разделить блокировку между процессами. Я понимаю, что способ поделиться блокировкой - это передать ее в качестве аргумента целевой функции. Однако я обнаружил, что даже подход ниже работает. Я не мог понять, как процессы разделяют эту блокировку. Может ли кто-нибудь объяснить, пожалуйста?

import multiprocessing as mp
import time


class SampleClass:

    def __init__(self):
        self.lock = mp.Lock()
        self.jobs = []
        self.total_jobs = 10

    def test_run(self):
        for i in range(self.total_jobs):
            p = mp.Process(target=self.run_job, args=(i,))
            p.start()
            self.jobs.append(p)

        for p in self.jobs:
            p.join()

    def run_job(self, i):
        with self.lock:
            print('Sleeping in process {}'.format(i))
            time.sleep(5)


if __name__ == '__main__':
    t = SampleClass()
    t.test_run()

2 ответа

Решение

В Windows (которую вы сказали, что используете), такие вещи всегда сводятся к деталям о том, как multiprocessing играет с pickleпотому что все границы процесса пересечения данных Python в Windows реализуются путем травления на передающей стороне (и отмены травления на принимающей стороне).

Мой лучший совет - избегать действий, которые вызывают такие вопросы, для начала;-) Например, код, который вы показали, взрывается в Windows под Python 2, а также взрывается под Python 3, если вы используете multiprocessing.Pool метод вместо multiprocessing.Process,

Это не просто блокировка, просто попытка привязать связанный метод (например, self.run_job) взрывается в Python 2. Подумайте об этом. Вы пересекаете границу процесса, и нет объекта, соответствующего self на приемном конце. К какому объекту относится self.run_job должен быть связан на приемном конце?

В Python 3 травление self.run_job также мариновать копию self объект. Вот и ответ: SampleClass объект, соответствующий self создается магией на приемном конце. Ясно, как грязь. tмаринованное, в том числе t.lock, Вот почему это "работает".

Смотрите это для более подробной информации о реализации:

Почему я могу передать метод экземпляра multiprocessing.Process, но не multiprocessing.Pool?

В конечном счете, вы будете страдать от наименьшего количества загадок, если будете придерживаться вещей, которые явно предназначались для работы: передавать вызываемые модулем глобальные объекты (ни, например, методы экземпляра или локальные функции), и явно передавать multiprocessing объекты данных (будь то экземпляр Lock, Queue, manager.listи тд и тп).

В операционных системах Unix новые процессы создаются через forkпримитивный.

forkПримитив работает путем клонирования адресного пространства памяти родительского процесса, присваивая его потомку. У потомка будет копия памяти родителя, а также файловых дескрипторов и общих объектов.

Это означает, что когда вы вызываете fork, если у родительского файла открыт файл, у дочернего элемента он тоже будет. То же самое относится к общим объектам, таким как трубы, сокеты и т. Д.

В Unix+CPython,Locksреализуются черезsem_openпримитив, который предназначен для совместного использования при разветвлении процесса.

Я обычно рекомендую не смешивать параллелизм (в частности, многопроцессорность) и ООП, потому что это часто приводит к недоразумениям такого рода.

РЕДАКТИРОВАТЬ:

Видел только сейчас, что вы используете Windows. Tim Peters дал правильный ответ. Ради абстракции Python пытается обеспечить независимое поведение ОС через свой API. При вызове метода экземпляра он выбирает объект и отправляет его по каналу. Таким образом, обеспечивая поведение, подобное для Unix.

Я бы порекомендовал вам прочитать руководство по программированию для многопроцессорной обработки. Ваша проблема решена, в частности, в первом пункте:

Избегайте общего состояния

Насколько это возможно, следует избегать смещения больших объемов данных между процессами.

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

Другие вопросы по тегам