Как многопроцессное разветвление Python работает в отношении совместного использования ресурсов - PullRequest
0 голосов
/ 28 июня 2019
import multiprocessing as mp
class Job:
    def __init__(self,name):
        self.name=name
class A:
    def __init__(self,x):
        self.x=x
    def run(self,job):
        self.x+=1
        print(id(self.x),self.x,job.name)

    def mul_process_test(self):
        j1=Job('hello')
        j2=Job('world')
        p1=mp.Process(target=self.run,args=(j1,))
        p2=mp.Process(target=self.run,args=(j2,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
if __name__ =='__main__':
    a=A(1)
    a.mul_process_test()
    print(id(a.x),a.x)

Результат приведенного выше кода:

10919360 2 hello
10919360 2 world
10919328 1

Кажется, self.x в двух процессах имеет одинаковый идентификатор, 10919360 (что не имеет смысла для меня), ноиметь другой идентификатор от основного процесса (что имеет смысл для меня).Я использую python3.5 в Linux, как говорится в документе, метод запуска по умолчанию использует способ, подобный форку, чтобы начать новый процесс.Мне было интересно, почему id self.x в двух процессах одинаковы.Есть ли что-то общее для трех процессов (основной процесс и два процесса, запущенные с mp.Process)?

1 Ответ

3 голосов
/ 28 июня 2019

id s в CPython (ссылочный интерпретатор Python) - это просто адреса памяти. И CPython (как деталь реализации) использует небольшой кэш int, так что все числа от -5 до 256 являются одиночными. Таким образом, ваши дочерние процессы копируют ту же таблицу виртуальных адресов из родительского и наследуют тот же маленький кэш int. Когда они вычисляют self.x += 1, они ищут то же кэшированное значение 2.

Теперь, технически, благодаря подсчету ссылок CPython, физическая память, лежащая в основе каждого процесса 2, не будет одинаковой (обновления счетчика ссылок вынуждают копировать копию страницы записи в дочерние элементы, как только на значения ссылаются, увеличивая счетчик ссылок). Но семантика копирования при записи сохраняет адрес виртуальной памяти, они просто переназначают базовые физические страницы, а CPython id сообщает (неизмененный) адрес виртуальной памяти. Поэтому для любого значения от -5 до 256 можно ожидать, что id s будет идентичным в fork -дедовых дочерних процессах. Вы ожидаете расхождения только со значениями, выходящими за этот диапазон, и даже тогда вы можете на некоторое время получить схожие идентификаторы, если бы поведение во время выполнения было таким же (потому что состояние распределителя также копируется в fork; до тех пор, пока что-то не станет расходящимся или недетерминированные изменения схемы распределения, адреса выделенной памяти будут продолжать следовать той же схеме).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...