A Radical Approach to Application Development / Радикальный подход к разработке приложений: 2.1 Myth 1: Lisp Needs a Compiler

Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

На самом деле, это самый главный миф. Если вы участвовали в групповых обсуждениях Lisp, то знаете, что компилятор играет главную роль. Может сложиться впечатление, что это почти синоним среды исполнения. Людям важно, какие действия компилятор производит с кодом и насколько эффективно. Если вам кажется, что программа на Lisp медленно выполняется, то вы решите, что вам требуется компилятор получше.

SauleSaulite 11.04.13 в 16:57

0

Идея интерпретируемого Lisp расценивается как старое заблуждение. Для современного Lisp требуется компилятор, а интерпретатор - это лишь полезное дополнение, и нужен для интерактивной отладки приложения. Он слишком медленный и раздутый для выполнения программ, которые уже находятся на этапе готовности к выпуску.

mmamkin 12.04.13 в 04:46

0

Мы уверены, что противоположная точка зрения верна. С одной стороны (и не только с философской точки зрения) скомпилированная программа на Lisp больше не является Lisp вообще. Это нарушает фундаментальное правило "формальной эквивалентности кода и данных". Получившийся код не содержит S-выражений и не может быть обработан Lisp. Исходный язык (Lisp) преобразовывется в другой язык (машинный код) с неизбежными несовместимостями на разных машинах.

SauleSaulite 12.04.13 в 17:20

0

На практике, компилятор усложняет систему в целом. Такие особенности, как стратегии множественного связывания, типизированные переменные и макросы были разработаны для удовлетворения нужд компиляторов. Система получается раздутой, потому что она должна поддерживать также и интерпретатор, и соответственно, две достаточно различные архитектуры,

SauleSaulite 12.04.13 в 17:21

0

Но стоит ли это затраченных усилий? Конечно, скорость выполнения выше, и создание компилятора интересно в целях обучения. Но мы утверждаем, что в повседневной жизни хорошо спроектированный "интерпретатор" часто может превзойти скомпилированную систему.

SauleSaulite 12.04.13 в 17:34

0

Вы понимаете, что на самом деле мы не говорим об "интерпретации". Lisp-система сразу конвертирует передаваемые ей данные во внутренние структуры указателей, которые называются "S-выражениями". Истинная "интерпретация" работает с одномерными кодами символов, и это существенно замедляет процесс выполнения. Lisp же "вычисляет" S-выражения быстро следуя по этим структурам указателей. Нет никаких поисков, так что ничего на самом деле не "интерпретируется". Но мы будем придерживаться этого привычного термина.

SauleSaulite 12.04.13 в 17:43

0

Программа на Lisp как S-выражение образует дерево исполняемых узлов. Код этих узлов написан обычно на оптимизированном С или ассемблере, поэтому задача интерпретатора состоит в том, чтобы передать управление от одного узла другому. Поскольку многие из этих встроенных функций Lisp очень мощные и выполняют много вычислений, большая часть времени выполнения приходится на узлы. Само дерево функционирует как своего рода клей.

SauleSaulite 12.04.13 в 17:52

0

Компилятор Lisp убирает немного этого клея и заменяет некоторые узлы с примитивной или потоковой функциональностью напрямую в машинный код. Но, поскольку в любом случае большая часть времени выполнения приходится на встроенные функции, эти улучшения не столь драматичны, как например у компилятора байт-кода Java, для которого каждый узел (байт-код) обладает сравнительно примитивной функциональностью.

SauleSaulite 12.04.13 в 17:57

0
+1

Конечно, компиляция сама по себе также требует довольно много времени. Сервер приложений часто исполняет исходные файлы Lisp на лету за один прогон и немедленно отбрасывает код, как только он выполнился. В таких случаях, либо изначально более медленный интерпретатор Lisp-системы, основанной на компиляторе, либо дополнительное время, затрачиваемое компилятором, будут значительно снижать общую производительность.

SauleSaulite 12.04.13 в 18:09

0

Внутренние структуры Pico Lisp были изначально разработаны для удобства интерпретации. Несмотря на то, что они были полностью написаны на C, и не были специально оптимизированы для скорости выполнения, никогда не было проблемы недостаточной производительности. Первая коммерческая система, написанная на Pico Lisp, представляла собой систему для обработки и ретуширования изображений, а также для создания макетов страниц для печати. Она была создана в 1988 году и использовалась на Mac II с ЦПУ 12 МГц и оперативной памятью 8 МБ. Конечно, не было компилятора Lisp, были только низкоуровневые манипуляции с пикселями и функции безье, написанные на C. Даже тогда, при работе на компьютере, в сотни раз медленнее современных, никто не жаловался на производительность.

SauleSaulite 15.04.13 в 02:51

0

Чисто ради интереса я установил CLisp и сравнил его с Pico Lisp ан примере простых тестов. Конечно, это не означает, что результаты тестов показывают полезность той или иной системы в качестве сервера приложений, но они дают приблизительное представление о производительности этих систем. Сначала, я попытался выполнить простую рекурсивную функцию Фибоначчи.
(defun fibo (N)
(if (< N 2)
1 (+ (fibo (- N 1)) (fibo (- N 2)) ) ) )

SauleSaulite 15.04.13 в 02:56

0

При вызове этой функции с параметром 30 (fibo 30), я получил следующие результаты (тестирование выполнялось на ноутбуке Pentium-I 266 МГц):
Pico (интерпретация) 12 секунд
CLisp интерпретация 37 секунд
CLisp компилированный за 7 секунд.
Интерпретатор CLisp почти в три раза медленнее, а компилятор чуть ли не в два раза быстрее Pico Lisp.

SauleSaulite 15.04.13 в 03:02

0

Однако функция Фибоначчи не очень хороший пример типичной Lisp-программы. Она состоит только из примитивного потока и арифметических функций, что легко оптимизируется компилятором и может быть написано прямо на C, если это критично по времени (в этом случае выполнение заняло бы всего 0.2 с)

mmamkin 15.04.13 в 03:55

0

Поэтому я взял другой крайний случай, с функцией, выполняющей обширную обработку списков:
(defun tst () (mapcar
(lambda (X) (cons
(car X) (reverse (delete (car X) (cdr X))) ) ) '((a b c a b c) (b c d b c d) (c d e c d e) (d e f d e f)) ) )

mmamkin 15.04.13 в 03:57

0

Вызвав эту функцию 1 млн раз, я получил:
Pico (интерпретация) 31 sec
CLisp интерпретация 196 sec
CLisp компилированный 80 sec
Теперь интерпретатор CLisp более чем в 6 раз медленнее, но к моему удивлению даже скомпилированный код в 2.58 раз медленнее чем Pico Lisp.

mmamkin 15.04.13 в 04:00

0

Может быть у CLisp медленный компилятор? И возможно код может быть ускорен с помощью некоторых трюков. Но эти результаты все равно оставляют много сомнений в том, могут ли быть оправданы накладные расходы на компиляцию. Возиться с оптимизацией компиляторов это последнее, что я хочу делать, когда дело касается логики приложения и когда пользователь все равно не заметит задержек.

mmamkin 15.04.13 в 04:06

0
Минутку...