Я изучаю Clojure и лучше разбираюсь в своем прогрессе. Я решил начать решение проблем Project Euler на языке (некоторые из которых я уже решил в C++ и Python). Проблема 1 выглядит следующим образом:Как проверить (сравнить) производительность Python против Clojure?
Если мы все натуральные числа меньше 10, кратные 3 или 5 , мы получаем 3, 5, 6 и 9. Сумма этих мультипликаторов составляет 23.
Найти сумму всех чисел, кратных 3 или 5 ниже 1000.
Вот мой первый пробег на решение Clojure:
(defn main1
([n]
(reduce +
(filter
#(or
(= 0 (mod % 3))
(= 0 (mod % 5)))
(range n)))))
Я тогда lõoke d в моей версии Python кода, который выглядит следующим образом:
import sys
import operator
from functools import reduce
def main(n=1000):
"""
returns solution up to but excluding n
"""
genexp = (num for num in range(1, n) if ((num % 3 == 0) or (num % 5 == 0)))
total = reduce(operator.add, genexp)
return total
if __name__ == "__main__":
if len(sys.argv) > 1:
print(main(int(sys.argv[1])))
else:
print(main())
Игнорирование дополнительных CLI-арг вещи я добавил в версии Python, единственным основным отличием является то, что я использовал filter
в Clojure вместо генератор. Я предполагаю, что я мог бы использоваться в Python с filter
тоже, но только ради аргумента, я сделал свой Clojure код более похож на код Python:
(defn main2
([n]
(reduce + (for [i (range n)
:let [div3 (= 0 (mod i 3))
div5 (= 0 (mod i 5))]
:when (or div3 div5)]
i))))
Это заставило меня задуматься - как я могу это тест функции для их сравнения? Для Python, это достаточно легко:
$ time python python/p0001.py 10000000
23333331666668
real 0m2.693s
user 0m2.660s
sys 0m0.018s
$ time python python/p0001.py 100000000
2333333316666668
real 0m26.494s
user 0m26.381s
sys 0m0.050s
Он идет до n=100,000,000
в разумные сроки (до 30 секунд). Как я могу запустить аналогичный тест для моих функций Clojure? Я предполагаю, что мне придется сначала скомпилировать код Clojure, прежде чем запускать его. Было бы это даже справедливым сравнением, учитывая, что код Python здесь не скомпилирован JIT?
В другом примечании, насколько идиоматичным является мой код Clojure (обе версии)? И какие хорошие рекомендации по стилю кода? Есть ли в стиле pep8 стиль-путеводитель? Или даже что-то похожее на версию Clojure pep20: «Zen of Python»?
«бы, что даже справедливое сравнение?» Нет, нет такого понятия, как справедливое сравнение языков. Все контрольные показатели в некотором роде ошибочны. Лучшее, что вы можете сделать, это решить, что * вы считаете важным в отношении языка и пытаетесь его измерить. Вы хотите измерить компиляцию + время выполнения? Вы хотите измерить использование кучи? Вы хотите сравнить среднюю зарплату младших инженеров, работающих с каждым языком? –
относительно вашего «как идиоматично мой код клоюра»? (1), если у вас нет функции многозначности, не часто встречается '(' вокруг вектора аргументов '([n] ...' (2) '(= 0 ...' часто выражается как ' (нуль? ... '(3) ваш отступ в основном правилен, но вы ищете руководство по стилю clojure, и вы получите хорошую информацию. (4) При выражении чисел со многими нулями рассмотрите использование научной нотации.' 100 000 000' в clojure тоже «1e8» .Все хорошая работа! Я бы предпочел рекомендацию по критерию. Я использую его почти ежедневно. Версия 100 000 000 показывает время 1,84s здесь FYI. – Josh
FYI: Это работает примерно в 1.1s для меня: '(пусть [п 100000000] (трансдукции (фильтр # (или (ноль (бэр% 3)) (ноль (бэр% 5)))) + (диапазон п?))) 'он использует преобразователи, чтобы избежать создания какой-либо коллекции. – ClojureMostly