Пытаясь внести некоторую оптимизацию для распараллеливания в модуле pystruct и в обсуждениях, пытаясь объяснить, почему я хотел создавать экземпляры пулов как можно раньше при выполнении и поддерживать их как можно дольше, повторно используя их, я понял, что знаю что это работает лучше всего, но я не знаю, почему.
Я знаю, что в системах * nix утверждается, что рабочий подпроцесс пула копирует при записи все глобальные переменные в родительском процессе. В целом это определенно так, но я думаю, что следует добавить предостережение: когда одна из этих глобальных переменных является особенно плотной структурой данных, такой как матрица numpy или scipy, кажется, что любые ссылки, скопированные в worker, на самом деле довольно хороши. даже если копируется не весь объект, поэтому создание новых пулов в конце выполнения может вызвать проблемы с памятью. Я обнаружил, что наилучшей практикой является создание пула как можно раньше, чтобы любые структуры данных были небольшими.
Я знал об этом некоторое время и разрабатывал его в приложениях на работе, но лучшее объяснение, которое я получил, это то, что я разместил в ветке здесь:
https://github.com/pystruct/pystruct/pull/129#issuecomment-68898032
Глядя на приведенный ниже скрипт Python, по существу, вы ожидаете, что свободная память на шаге создания пула в первом запуске и шаге создания матрицы во втором будут в основном равными, как и в обоих завершаемых вызовах пула. Но их никогда не бывает, всегда (если, конечно, на машине не происходит что-то еще) больше свободной памяти, когда вы сначала создаете пул. Этот эффект увеличивается со сложностью (и размером) структур данных в глобальном пространстве имен во время создания пула (я думаю). У кого-нибудь есть хорошее объяснение этому?
Я сделал эту маленькую картинку с циклом bash и R-скриптом ниже, чтобы проиллюстрировать, показывая свободную память в целом после создания пула и матрицы, в зависимости от порядка:
pool_memory_test.py:
import numpy as np
import multiprocessing as mp
import logging
def memory():
"""
Get node total memory and memory usage
"""
with open('/proc/meminfo', 'r') as mem:
ret = {}
tmp = 0
for i in mem:
sline = i.split()
if str(sline[0]) == 'MemTotal:':
ret['total'] = int(sline[1])
elif str(sline[0]) in ('MemFree:', 'Buffers:', 'Cached:'):
tmp += int(sline[1])
ret['free'] = tmp
ret['used'] = int(ret['total']) - int(ret['free'])
return ret
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--pool_first', action='store_true')
parser.add_argument('--call_map', action='store_true')
args = parser.parse_args()
if args.pool_first:
logging.debug('start:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
p = mp.Pool()
logging.debug('pool created:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
biggish_matrix = np.ones((50000,5000))
logging.debug('matrix created:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
print memory()['free']
else:
logging.debug('start:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
biggish_matrix = np.ones((50000,5000))
logging.debug('matrix created:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
p = mp.Pool()
logging.debug('pool created:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
print memory()['free']
if args.call_map:
row_sums = p.map(sum, biggish_matrix)
logging.debug('sum mapped:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
p.terminate()
p.join()
logging.debug('pool terminated:\n\t {}\n'.format(' '.join(['{}: {}'.format(k,v)
for k,v in memory().items()])))
pool_memory_test.sh
#! /bin/bash
rm pool_first_obs.txt > /dev/null 2>&1;
rm matrix_first_obs.txt > /dev/null 2>&1;
for ((n=0;n<100;n++)); do
python pool_memory_test.py --pool_first >> pool_first_obs.txt;
python pool_memory_test.py >> matrix_first_obs.txt;
done
pool_memory_test_plot.R:
library(ggplot2)
library(reshape2)
pool_first = as.numeric(readLines('pool_first_obs.txt'))
matrix_first = as.numeric(readLines('matrix_first_obs.txt'))
df = data.frame(i=seq(1,100), pool_first, matrix_first)
ggplot(data=melt(df, id.vars='i'), aes(x=i, y=value, color=variable)) +
geom_point() + geom_smooth() + xlab('iteration') +
ylab('free memory') + ggsave('multiprocessing_pool_memory.png')
РЕДАКТИРОВАТЬ: исправлена небольшая ошибка в скрипте, вызванная чрезмерным поиском/заменой и повторным запуском.
EDIT2: нарезка "-0"? Вы можете сделать это? :)
EDIT3: лучший скрипт python, цикл bash и визуализация, на данный момент все в порядке с этой кроличьей норой :)
-0
не является индексом. это нотация среза - person Himal   schedule 07.01.2015