#python #python-3.x #subprocess #multiprocessing
#python #python-3.x #подпроцесс #многопроцессорность
Вопрос:
В следующей программе, когда я добавляю процесс в список (что, казалось бы, бессмысленно), он выполняется так, как ожидалось. Но если я удаляю добавление, деструктор процессов вызывается много раз, прежде чем он будет запущен. Есть только n
конструкции, но (n)(n 1)/2
(где n
— количество процессов) разрушения. Это наводит меня на мысль, что каждый процесс копируется в каждый новый процесс, а затем немедленно уничтожается. Возможно, именно так работает модуль многопроцессорной обработки. Это имеет смысл, поскольку каждый процесс является ответвлением текущего. Но в чем смысл добавления в список? Почему простое выполнение этого останавливает это поведение?
Вот тест и пример вывода:
import multiprocessing
class _ProcSTOP:
pass
class Proc(multiprocessing.Process):
def __init__(self, q, s):
s.i = 1
self._i = s.i
self._q = q
print('constructing:', s.i)
super().__init__()
def run(self):
dat = self._q.get()
while not dat is _ProcSTOP:
self._q.task_done()
dat = self._q.get()
self._q.task_done()
print('returning: ', self._i)
def __del__(self):
print('destroying: ', self._i)
if __name__ == '__main__':
q = multiprocessing.JoinableQueue()
s = multiprocessing.Manager().Namespace()
s.i = 0
pool = []
for i in range(4):
p = Proc(q, s)
p.start()
pool.append(p) # This is the line to comment
for i in range(10000):
q.put(i)
q.join()
for i in range(4):
q.put(_ProcSTOP)
q.join()
print('== complete')
Пример вывода с добавлением:
constructing: 1
constructing: 2
constructing: 3
constructing: 4
returning: 3
returning: 2
== complete
returning: 1
returning: 4
destroying: 4
destroying: 3
destroying: 2
destroying: 1
Пример вывода без добавления:
constructing: 1
constructing: 2
constructing: 3
destroying: 1
constructing: 4
destroying: 1
destroying: 2
destroying: 3
destroying: 1
destroying: 2
returning: 1
returning: 4
returning: 2
== complete
returning: 3
destroying: 1
destroying: 3
destroying: 2
destroying: 4
Комментарии:
1. Как вы думаете, это как-то связано со сборкой мусора? Симптомы указывают на то, что необходимо сохранить ссылку на экземпляр класса.
2. @Dave. Это хороший момент. Я подозреваю, что вы на правильном пути.
Ответ №1:
Добавление объекта в список предотвратит его удаление в дочерних процессах, потому что после разветвления он вызовет «os._exit()» вместо очистки всего стека
Соответствующий код находится в multiprocessing/forking.py (конструктор Popen, который вызывается в «p.start()»)
self.pid = os.fork()
if self.pid == 0:
if 'random' in sys.modules:
import random
random.seed()
code = process_obj._bootstrap()
sys.stdout.flush()
sys.stderr.flush()
os._exit(code)
Где _bootstrap настраивает новый процесс и вызывает «run» (код находится в multiprocessing/process.py )