При использовании Python ThreadPool для распараллеливания задачи, интенсивно использующей ЦП, кажется, что память, используемая рабочими процессами, накапливается, а не освобождается. Я попытался упростить проблему:
import numpy as np
from multiprocessing.pool import ThreadPool
def worker(x):
# Bloat the memory footprint of this function
a = x ** x
b = a + x
c = x / b
return hash(c.tobytes())
tasks = (np.random.rand(1000, 1000) for _ in range(500))
with ThreadPool(4) as pool:
for result in pool.imap(worker, tasks):
assert result is not None
При запуске этого фрагмента можно легко заметить огромный скачок в объеме памяти, используемом Python. Однако я ожидал, что это будет иметь почти такое же поведение, как
for task in tasks:
assert worker(task) is not None
чья стоимость памяти незначительна.
Как мне изменить фрагмент, чтобы применить функцию worker к каждому массиву с помощью ThreadPool?






Оказывается, объяснение довольно простое. Изменение примера для создания случайного массива только внутри работника решит проблему:
def worker(x):
x = x()
# Bloat the memory footprint of this function
a = x ** x
b = a + x
c = x / b
return hash(c.tobytes())
tasks = (lambda: np.random.rand(1000, 1000) for _ in range(500))
Похоже, что ThreadPools.imap внутренне превратит генератор tasks в список или что-то подобное. Это, конечно, потребует одновременного хранения в памяти всех 500 случайных массивов.