У меня нет большого опыта в программировании, но я немного знаю Python3, и сейчас я делаю свои первые детские шаги в изучении Pharo. Я все еще не знаком с объектно-ориентированным программированием или обозревателем классов, но я уже прошел учебник ProfStef и играюсь с небольшими программами на Playground, чтобы ознакомиться с синтаксисом.
Одной из первых вещей, которые меня заинтересовали, было сравнение двух языков с точки зрения скорости, поскольку я где-то читал, что в Pharo встроен JIT-компилятор. Поэтому я написал небольшой причудливый скрипт на обоих языках, который генерирует 8 миллионов чисел. , фильтрует 1/3 из них, вычисляет 1/sqrt(x) для каждого, суммирует результаты и повторяет процесс сто раз, каждый раз немного изменяя интервалы, снова суммируя результаты в конце и измеряя время всего процесса. . Не правильный тест, просто упражнение, чтобы получить оценку порядка величины, но я старался, чтобы обе версии были как можно более похожими.
Версия Python 3:
import time, math
mega = lambda n: sum([1/math.sqrt(1 + i + n) for i in range(8000000) if (i + 1) // 3 == 0])
start = time.time()
print(sum([mega(n + 1) for n in range(100)]))
stop = time.time() - start
print(stop)
Результаты с Python 3.8.5 (по умолчанию, 28 июля 2020 г., 12:59:40):
34.7701230607214
52.75216603279114
Фаро 8 версия:
| mega range start stop |.
range := [:n | (((1 to: 8000000) select: [:j | (j quo: 3) = 0]) collect: [:i | 1 / (n + i) sqrt]) sum].
start := DateAndTime now.
Transcript show: (((1 to: 100) collect: [:n | range value: n]) sum); cr.
stop := (DateAndTime now - start) asSeconds.
Transcript show: stop; cr.
Результаты на Pharo-8.0.0+build.1141.sha.1b7a8d8203fce2a57794451f555bba4222614081 (64 бит):
34.7701230607214
45
Как я и ожидал, версия Pharo работала быстрее, но с небольшим отрывом, 45 секунд против чуть более 52 секунд для Python. Это заняло примерно на 13% меньше времени. Так что я предполагаю, что их скорость примерно одного порядка. Это типичная ситуация?
Такой тест мало о чем говорит. Основная причина в том, что основная часть вычислений состоит в многократной отправке одних и тех же сообщений экземплярам одних и тех же классов (quo:
и =
для select:
и /
, +
, sqrt
для collect:
и т. д.). Это означает, что трудоемкая (внутренняя) операция, такая как поиск метода, выполняется только один раз, а затем задерживается во встроенных кэшах. В результате у вас может быть система, которая превосходит другую при выполнении этих тестов и намного медленнее при запуске «настоящего» приложения. Помимо (моно или полиморфных) встроенных кешей, которые уменьшают потребность в поиске методов, другие методы, которые имеют значение, — это производительность сборщика мусора, встраивание методов (которое заменяет отправляющие сайты копией целевого кода), размещение регистров. (для минимизации доступа к памяти), производительность сообщения become:
и т. д. Множество факторов делает желательным измерение более сложных фрагментов кода, пытаясь использовать известные узкие места, как те, которые я только что упомянул. Иногда небольшое изменение может выявить скрытые сильные (или слабые) стороны вашей системы. Поэтому я предлагаю, чтобы для проведения такого рода анализа вы должны немного постараться и разработать тесты, направленные на измерение того, как система реагирует на определенный вид стресса.
Хотя это еще не так идиоматически,
| range start stop |.
range := [ :n | (1 to: 8000000) inject: 0 into: [:sum :in |
((in quo: 3) = 0 )
ifTrue: [1 / ( n + in) sqrt + sum]
ifFalse: [sum]]].
start := DateAndTime now.
Transcript show: (((1 to: 100) collect: [:n | range value: n]) sum); cr.
stop := (DateAndTime now - start) asSeconds.
Transcript show: stop; cr.
в 2,5 раза быстрее. Что как бы подчеркивает точку зрения Леандро.
Я запустил вашу версию на своей машине, и на самом деле это заняло всего 19 секунд. Впечатляющий! Спасибо.
Спасибо вам за разъяснение. Я думаю, что мне понадобится некоторое время, чтобы изучить язык, прежде чем я смогу разработать правильные тесты. Поскольку другие люди, вероятно, делали это раньше, я просто спросил.