Отмеченный это как ответ начал более простую тему вокруг, где вопрос скорости действительно кажутсяPython многопроцессорной обработки текста проблема производительности экстракция против Perl эквивалент
Python slow read performance issue
Спасибо за все комментарии на сегодняшний день, очень полезный
У меня есть около 40M XML-файлов, распространяемых (не равномерно) через ок. 60K подкаталоги, структура основана на 10 значное число разделить так:
12/34/56/78/90/files.xml
У меня есть сценарий PERL, который работает против файлов тянущих значение одно поле и распечатает значение и имя файла. Скрипт Perl обернут в сценарий bash, который запускает максимум 12 параллельных экземпляров в списке всех каталогов на глубине 2, а затем идет по каждому из них и обрабатывает файлы на нижнем уровне по мере их обнаружения.
Принимая кэширование диска из нескольких прогонов время Unix процесса возвращается приблизительно:
real 37m47.993s
user 49m50.143s
sys 54m57.570s
Я хотел перенести это питон скрипт (в качестве учебного упражнения и теста), поэтому создается следующее (после много читал на методы питона для различных вещей):
import glob, os, re
from multiprocessing import Pool
regex = re.compile(r'<field name="FIELDNAME">([^<]+)<', re.S)
def extractField(root, dataFile):
line = ''
filesGlob = root + '/*.xml'
global regex
for file in glob.glob(filesGlob):
with open(file) as x:
f = x.read()
match = regex.search(f)
line += file + '\t' + match.group(1) + '\n'
dataFile.write(line)
def processDir(top):
topName = top.replace("/", "")
dataFile = open('data/' + topName + '.data', 'w')
extractField(top, dataFile)
dataFile.close()
filesDepth5 = glob.glob('??/??/??/??/??')
dirsDepth5 = filter(lambda f: os.path.isdir(f), filesDepth5)
processPool = Pool(12)
processPool.map(processDir, dirsDepth5)
processPool.close()
processPool.join()
Но как бы я ни порезать содержание, когда я запускаю его Юниксовое время дает мне такой результат:
real 131m48.731s
user 35m37.102s
sys 48m11.797s
Если я запускаю скрипт python и perl в одном потоке с небольшим подмножеством (который заканчивается полностью кэшированным), поэтому нет диска io (в соответствии с iotop), тогда скрипты выполняются в почти одинаковые времена.
Единственный вывод, о котором я могу думать до сих пор, заключается в том, что файл io гораздо менее эффективен в сценарии python, чем в скрипте perl, поскольку это, по-видимому, является проблемой io.
Надеюсь, этого достаточно, мой вопрос: я делаю что-то глупое или отсутствует трюк, поскольку у меня заканчиваются идеи, но я не могу поверить, что io вызывает такую разницу во времени обработки.
Оцените любые указатели и предоставит больше информации по мере необходимости.
Благодаря
Si
Для справки скрипт Perl находится ниже:
use File::Find;
my $cwd = `pwd`;
chomp $cwd;
find(\&hasxml, shift);
sub hasxml {
if (-d) {
my @files = <$_/*.xml>;
if (scalar(@files) > 0) {
process("$cwd/${File::Find::dir}/$_");
}
}
}
sub process {
my $dir = shift;
my @files = <$dir/*.xml>;
foreach my $file (@files) {
my $fh;
open($fh, "< $file") or die "Could not read file <$file>";
my $contents = do { local $/; <$fh> };
close($fh);
my ($id) = $contents =~ /<field name="FIELDNAME">([^<]+)<\/field>/s;
print "$file\t<$id>\n";
}
}
может быть, это поможет вам: http://stackoverflow.com/questions/14863224/efficient-reading-of-800-gb-xml-file-in-python-2-7 Я думаю, вы должны профилировать свое приложение, чтобы узнать, где он проводит больше всего времени, в противном случае это немного угадывает ... –
Я посмотрю спасибо, а должен добавить файлы XML, которые я читаю, не более 4K каждый в но я попробую буферизацию, упомянутую для просмотра. Я пробовал профилирование, но когда я запускаю - python -m cProfile script.py это barfs, я подозреваю, что он не знает, как обрабатывать элемент многопроцессорности, но, признаюсь, я не смотрел на ошибку подробно. – Simon
user/sys ниже (подсказка python выполняется быстрее), но реальная намного выше (намекая, что мы не получаем распараллеливание) ... Протокол parent/child имеет большое значение. Попробуйте 'processPool.map (processDir, dirsDepth5, chunksize = 16)', который отправляет задания более крупными партиями, чтобы узнать, имеет ли это значение. – tdelaney