Параметр chunksize
для pool.map
является причиной вашей путаницы.Очевидно, он выберет автоматическую настройку chunksize = 2 для вашей настройки, потому что вы получите результат, который вы наблюдали, также с явной установкой chunksize=2
.
С chunksize=1
вы получите [[1], [1], [1], [1], [1]]
, а с chunksize=3
вы получите [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1], [1, 1]]
.
Если вы расширите свой код распечатками, вы сможете наблюдать за тем, что происходит:
import multiprocessing as mp
def job(l):
print(f'before append {l}')
l.append(1)
print(f'after append {l}')
return l
if __name__ == "__main__":
pool = mp.Pool(1)
my_list = []
out = pool.map(job, [my_list for _ in range(5)], chunksize=2)
pool.close()
pool.join()
print(out)
Это даст вам такой вывод:
before append []
after append [1]
before append [1]
after append [1, 1]
before append []
after append [1]
before append [1]
after append [1, 1]
before append []
after append [1]
[[1, 1], [1, 1], [1, 1], [1, 1], [1]]
Process finished with exit code 0
Вы можете видеть, что «перед добавлением» начинается только три раза с пустым списком, а не пять раз, как вы ожидаете.Это потому, что с chunksize=2
и пятью элементами в итерируемом у вас есть 5/2 = 2,5 задачи.Половина задачи невозможна, поэтому у вас есть 3 задачи: 2 задачи с кусочками из двух элементов и одна задача с кусочком из одного элемента.
Теперь для первых двух задач перваявыполнение вашей функции job
получает пустой список без добавлений и добавляет 1
.Затем второе выполнение получает тот же список, что и первое изменение, только что измененное, потому что ваши элементы являются просто ссылками на тот же список в этой задаче.Второе выполнение также изменяет результат первого выполнения, поскольку оба изменяют один и тот же базовый объект.После второго выполнения задача завершается, и результат двух выполнений [[1, 1], [1, 1]] возвращается родителю.Это происходит, как мы уже говорили, для первых двух задач.
Третья задача имеет только одно выполнение job
, и ее результат не модифицируется второй, поэтому результат только [1].
Если вы добавите for obj in out: print(id(obj))
в конце своего кода, вы увидите, что в результате вы получите три разных идентификатора для трех отдельных списков, столько же задач было создано для обработки вашего итерируемого (CPython).:
140584841382600
140584841382600
140584841383432
140584841383432
140584841383368