Почему 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 в вашей системе, то, возможно, будет существенный выигрыш в производительности с простым псевдонимом.

Другие вопросы по тегам