Я пытаюсь выполнить вычисления Монте-Карло параллельно, используя python. Проблема чрезвычайно параллельна: мне нужно вычислить функцию N раз и сложить результат вместе, каждое вычисление является независимым, и сложение является простым сложением между таблицами.
До сих пор я пробовал два подхода:
Использование multiprocessing.map()
и затем python reduce
. Проблема в том, что мне не хватает памяти, потому что карта хранит все данные, даже если мне это не нужно. Код выглядит следующим образом:
from multiprocessing import Pool
import tqdm
import numpy as np
n_cpu = 8
pool = Pool(n_cpu)
out1 = list(tqdm.tqdm(pool.imap_unordered(f, args, chunksize = 1000)))
out = reduce(np.add, out1)
Таким образом, я получаю плохое масштабирование с помощью n_cpu
, и код вылетает из-за ошибки памяти, если размер ввода len(args)
слишком велик.
Я попытался решить, используя pyspark
и следующий код:
import pyspark, findspark
import numpy as np
findspark.init()
number_cores = 8
memory_gb = 8
conf = (
pyspark.SparkConf()
.setMaster('local[{}]'.format(number_cores))
.set('spark.driver.memory', '{}g'.format(memory_gb))
)
sc = pyspark.SparkContext(conf=conf)
out = sc.parallelize(range(N_samples)).repartition(number_cores).map(function).reduce(lambda a, b: np.add(a, b))
Перераспределение сделано явно для ясности и равно числу ядер потому что я думал, что это лучший способ сделать это, так как функция для вычисления требует больших вычислительных ресурсов. Проблема в том, что я получаю производительность, аналогичную методу multiprocessing
.
Мой вопрос:
Есть ли способ улучшить масштабирование кода с количеством ядер? Есть ли способ использовать многопроцессорность imap_unordered()
и уменьшить его до завершения вычислений?