Почему pyp (python) однострочный такой медленный?
Я пытаюсь конвертировать мои perl однострочные в pyp. Моя первая попытка была любезно дана мне как ответ на другой вопрос
pyp "mm | p if n==0 else (p[:-2] + [(int(x)%12) for x in p[-2:]]) | mm"
Однако это оказывается удивительно медленным. Если я создаю тестовый файл с помощью
for j in xrange(50000):
print ",".join(str(i) for i in [random.choice(xrange(1000)) for i in xrange(8)])
а потом беги
time (cat testmedium.txt |~/.local/bin/pyp "mm | p if n==0 else (p[:-2] + [(int(x)%12) for x in p[-2:]]) | mm" > /dev/null)
я получил
real 1m27.889s
user 1m26.941s
sys 0m0.688s
Однако эквивалент в Perl почти мгновенный.
time (cat testmedium.txt |perl -l -a -F',' -p -e'if ($. > 1) { $F[6] %=12; $F[7] %= 12;$_ = join(q{,}, @F[6,7]) }' > /dev/null)
real 0m0.196s
user 0m0.192s
sys 0m0.012s
Для больших тестовых файлов разница еще более существенная.
2 ответа
Этот код...
import sys
for index,line in enumerate(sys.stdin):
if index == 0:
print line
else:
values = line.split(',')
values[-2:] = [str(int(x)%12) for x in values[-2:]]
print ','.join(values)
выполняется за секунду (используя тестовый файл, сгенерированный тем же методом, что и вы):
$ time (cat test.txt | python foo.py > /dev/null)
real 0m0.363s
user 0m0.339s
sys 0m0.032s
Так что, если вы сталкиваетесь с проблемами, это, вероятно, неэффективность с чем-то pyp
пытается сделать.
Это косвенный ответ на ваш вопрос @marshall.
Во-первых, я бы сказал, что для меня самым большим преимуществом pyp является не необходимость изучать другой язык, и я обычно не имею дело с большими объемами данных, поэтому он хорошо подходит для моих нужд. Кроме того, я понимаю, что были также некоторые ориентированные на скорость оптимизации для pyp, которые могли повлиять на проблему, которую вы описываете.
Я подумал, может ли pypy предоставить более быструю версию pyp, поэтому я создал псевдоним для pyp:
alias 'pl=pypy /usr/bin/pyp'
Затем я запустил эту команду с pyp и pl
lr | pl "'doc',p, p.replace('e','EEE')+'.xpg' | pp.reverse() | ''.join(p)" | pl "d|u"
где lr - псевдоним для ls -R + ls -A, просто чтобы создать длинный рекурсивный список для определения времени операции.
Результаты для pyp составили 8,04 секунды с использованием Python 2,7,6 и 4,46 секунды для псевдонима. Для гораздо большего набора каталогов это было 470 и 250 секунд. Python работает на 100% от одного ядра во время этой операции, как и PyPy.
Так что если у вас есть pypy в вашей системе, то, возможно, будет существенный выигрыш в производительности с простым псевдонимом.