Почему (python|ruby) интерпретируется?

В случае, если N априорно не фиксируется:

 for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
18
задан DigitalRoss 2 December 2009 в 00:02
поделиться

12 ответов

Google App Engine

Я бы написал это на движке приложений Google (python), потому что:

  • Он хорошо масштабируется.
  • У него хороший API электронной почты.
  • Это имеет очередь задач с хорошим api для доступа к нему.
  • Поскольку python - действительно хороший язык.
  • Это (относительно) дешевый.

PHP

Если бы я реализовал его на PHP, я бы

  • ] Найдите себе хороший SMTP-сервер, который позволит вам отправлять такой объем писем, потому что Gmail не позволяет отправлять такие объемы. Я уверен, что это будет стоить вам денег.
  • Найдите себе приличную почтовую библиотеку PHP для отправки сообщений, например, с помощью PHPMailer, как вы сказали.
  • Используйте очередь сообщений, например beanstalkd, чтобы помещать сообщения электронной почты в очередь и отправил письмо асинхронно. Во-первых, потому что с этим у пользователя будет более быстрая загрузка страницы. Во-вторых, с помощью очереди сообщений, такой как beanstalkd, вы можете лучше регулировать скорость отправки, что предотвратит перегрузку вашего компьютера работой. Вам понадобится ssh-доступ к серверу для компиляции (установки) beanstalkd. Вы можете найти beanstalkd по адресу beanstalkd
  • . Вам также понадобится доступ по ssh для запуска PHP-скрипта в фоновом режиме, который будет обрабатывать очередь сообщений. Вы можете найти beanstalkd-client на php beanstalkd-client

на php / apache / webpage

Это страница, с которой вы будете отправлять сообщения пользователю. С этой страницы вы отправите сообщение в beanstalkd, написав что-нибудь в следующих строках:

// register Pheanstalk class loader
require_once('pheanstalk_init.php');
$pheanstalk = new Pheanstalk('127.0.0.1');
$message = ""; // This would contain your message
$pheanstalk->put(json_encode($message);

Вы должны поместить сообщения в очередь сообщений с помощью команды put

Из длительного PHP-скрипта в фоновом режиме:

Код будет выглядеть что-то вроде этого: но может и нет (из-за более медленного запуска и большего объема памяти), особенно когда типы также должны быть выведены или специализированы как часть генерации кода. Генерировать машинный код без вывода типа или специализации легко, если вы этого хотите, например freeze сделает это за вас, но на самом деле он не дает преимуществ, которые приписывают ему «фетишисты машинного кода». Например, вместо крошечного "hello world" .pyc вы получаете исполняемый двоичный файл размером от 1,5 до 2 МБ - особого смысла нет! -). Этот исполняемый файл является автономным и распространяется как таковой, но он будет работать только в очень узком диапазоне операционных систем и архитектур ЦП, поэтому в большинстве случаев компромиссы весьма сомнительны. И время, необходимое для подготовки исполняемого файла, действительно довольно велико,

16
ответ дан 30 November 2019 в 05:42
поделиться

Merely replacing an interpreter with a compiler won't give you as big a performance boost as you might think for a language like Python. When most time is actually spend doing symbolic lookups of object members in dictionaries, it doesn't really matter if the call to the function performing such lookup is interpreted, or is native machine code - the difference, while not quite negligible, will be dwarfed by lookup overhead.

To really improve performance, you need optimizing compilers. And optimization techniques here are very different from what you have with C++, or even Java JIT - an optimizing compiler for a dynamically typed / duck typed language such as Python needs to do some very creative type inference (including probabilistic - i.e. "90% chance of it being T" and then generating efficient machine code for that case with a check/branch before it) and escape analysis. This is hard.

8
ответ дан 30 November 2019 в 05:42
поделиться

Я думаю, что главная причина интерпретируемых языков - это переносимость. Как программист, вы можете написать код, который будет работать в интерпретаторе, а не в конкретной ОС. Таким образом, ваши программы ведут себя более единообразно на разных платформах (больше, чем на скомпилированных языках). Еще одно преимущество, о котором я могу думать, заключается в том, что легче иметь систему динамических типов в интерпретируемом языке. Я думаю, что создатели языка думали о том, чтобы создать язык, на котором программисты могут быть более продуктивными благодаря автоматическому управлению памятью, системе динамических типов и метапрограммированию, превосходящему любую потерю производительности из-за интерпретируемого языка. Если вас беспокоит производительность, вы всегда можете скомпилировать язык в машинный код, используя такой метод, как JIT-компиляция.

6
ответ дан 30 November 2019 в 05:42
поделиться

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

2
ответ дан 30 November 2019 в 05:42
поделиться

Сегодня больше нет четкого различия между «скомпилированными» и «интерпретируемыми» языками. На самом деле Python компилируется так же, как и Java, с единственными отличиями:

  • Компилятор Python намного быстрее, чем компилятор Java.
  • Python автоматически компилирует исходный код по мере его выполнения, нет отдельной «компиляции» требуемый шаг
  • Байт-код Python отличается от байт-кода JVM

В Python даже есть функция compile () , которая является интерфейсом для компилятора.

Похоже, что вы проводите различие между "динамически типизированными" и "статически типизированными" языками. В динамических языках, таких как Python, вы можете написать такой код:

def fn(x, y):
    return x.foo(y)

Обратите внимание, что типы x и y не указаны. Во время выполнения эта функция будет смотреть на x , чтобы узнать, есть ли у нее функция-член с именем foo , и, если да, вызовет ее с y . В противном случае будет выдана ошибка выполнения, указывающая, что такая функция не найдена. Такой вид поиска во время выполнения намного проще представить с использованием промежуточного представления, такого как байт-код, где виртуальная машина времени выполнения выполняет поиск вместо того, чтобы генерировать машинный код для выполнения самого поиска (или вызвать функцию для выполнения поиска, которая является байт-код все равно подойдет).

У Python есть проекты, такие как Psyco , PyPy и Unladen Swallow , которые используют различные подходы к компиляции объектного кода Python во что-то ближе к нативному коду. В этой области ведутся активные исследования, но (пока) нет простого ответа.

и в таком случае назовем его с помощью y . В противном случае будет выдана ошибка выполнения, указывающая, что такая функция не найдена. Такой вид поиска во время выполнения намного проще представить с использованием промежуточного представления, такого как байт-код, где виртуальная машина времени выполнения выполняет поиск вместо того, чтобы генерировать машинный код для выполнения самого поиска (или вызвать функцию для выполнения поиска, которая является байт-код все равно подойдет).

У Python есть проекты, такие как Psyco , PyPy и Unladen Swallow , которые используют различные подходы к компиляции объектного кода Python во что-то ближе к машинному коду. В этой области ведутся активные исследования, но (пока) нет простого ответа.

и в таком случае назовем его с помощью y . В противном случае будет выдана ошибка выполнения, указывающая, что такая функция не найдена. Такой вид поиска во время выполнения намного проще представить с использованием промежуточного представления, такого как байт-код, где виртуальная машина времени выполнения выполняет поиск вместо того, чтобы генерировать машинный код для выполнения самого поиска (или вызвать функцию для выполнения поиска, которая является байт-код все равно подойдет).

У Python есть проекты, такие как Psyco , PyPy и Unladen Swallow , которые используют различные подходы к компиляции объектного кода Python во что-то ближе к машинному коду. В этой области ведутся активные исследования, но (пока) нет простого ответа.

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

У Python есть проекты, такие как Psyco , PyPy и Unladen Swallow , которые используют различные подходы к компиляции объектного кода Python во что-то ближе к машинному коду. В этой области ведутся активные исследования, но (пока) нет простого ответа.

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

У Python есть проекты, такие как Psyco , PyPy и Unladen Swallow , которые используют различные подходы к компиляции объектного кода Python во что-то ближе к машинному коду. В этой области ведутся активные исследования, но (пока) нет однозначного ответа.

вызвать функцию для поиска, что и так будет делать байт-код).

У Python есть такие проекты, как Psyco , PyPy и Unladen Swallow которые используют различные подходы к компиляции объектного кода Python в нечто более близкое к собственному коду. В этой области ведутся активные исследования, но (пока) нет однозначного ответа.

вызвать функцию для поиска, что и так будет делать байт-код).

У Python есть такие проекты, как Psyco , PyPy и Unladen Swallow которые используют различные подходы к компиляции объектного кода Python в нечто более близкое к собственному коду. В этой области ведутся активные исследования, но (пока) нет однозначного ответа.

5
ответ дан 30 November 2019 в 05:42
поделиться

Усилия, необходимые для создания хорошего компилятора, генерирующего собственный код для нового языка, ошеломляют . Небольшие исследовательские группы обычно занимают от 5 до 10 лет (примеры: SML / NJ , Haskell, Clean, Cecil, lcc , Objective Caml , MLton и многие другие). И когда рассматриваемый язык требует проверки типов и принятия других решений во время выполнения, разработчику компилятора приходится работать намного усерднее, чтобы получить хорошую производительность в машинном коде (отличный пример см. В работе Крейга Чемберса, а затем Урса Хельзле). Самостоятельная). Прирост производительности, на который вы могли надеяться, труднее реализовать, чем вы думаете. Этот феномен частично объясняет , почему интерпретируется так много динамически типизированных языков .

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

Наконец, хотя существуют быстрые компиляторы и медленные интерпретаторы, обычно легче ускорить цикл редактирование-перевод-идти с помощью интерпретатора. (Некоторые хорошие примеры быстрых компиляторов см. В вышеупомянутом lcc , а также в компиляторе Кена Томпсона go . Пример относительно медленного интерпретатора см. В GHCi . GHCi . 1117672] в то время как перенос компиляторов на новую машинную архитектуру требует значительных усилий (и это проблема, над которой я лично работал более 20 лет, с небольшим перерывом для хорошего поведения). Таким образом, интерпретатор - это способ быстро охватить широкую аудиторию.

Наконец, хотя существуют быстрые компиляторы и медленные интерпретаторы, обычно легче ускорить цикл редактирование-перевод-вперед с помощью интерпретатора. (Некоторые хорошие примеры быстрых компиляторов см. В вышеупомянутом lcc , а также в компиляторе Кена Томпсона go . Пример относительно медленного интерпретатора см. В GHCi . GHCi . 1117672] в то время как перенос компиляторов на новую машинную архитектуру требует значительных усилий (и это проблема, над которой я лично работал более 20 лет, с небольшим перерывом для хорошего поведения). Таким образом, интерпретатор - это способ быстро охватить широкую аудиторию.

Наконец, хотя существуют быстрые компиляторы и медленные интерпретаторы, обычно легче ускорить цикл редактирование-перевод-идти с помощью интерпретатора. (Некоторые хорошие примеры быстрых компиляторов см. В вышеупомянутом lcc , а также в компиляторе Кена Томпсона go . Пример относительно медленного интерпретатора см. В GHCi . GHCi . 1117672] Как правило, легче ускорить цикл редактирования-перевода-идти с помощью переводчика. (Хорошие примеры быстрых компиляторов см. В вышеупомянутом lcc , а также в компиляторе Кена Томпсона go . Пример относительно медленного интерпретатора см. В GHCi . . 1117672] Как правило, легче ускорить цикл редактирования-перевода-идти с помощью переводчика. (Хорошие примеры быстрых компиляторов см. В вышеупомянутом lcc , а также в компиляторе Кена Томпсона go . Пример относительно медленного интерпретатора см. В GHCi . . 1117672]

5
ответ дан 30 November 2019 в 05:42
поделиться

На компилируемом языке цикл, в который вы попадаете при создании программного обеспечения, следующий:

  1. Внести изменения
  2. Скомпилировать изменения
  3. Проверить изменения
  4. goto 1

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

Это не обязательно та причина, по которой разработчики python | ruby ​​думали об этом, но имейте в виду, что «Насколько эффективно машина это выполняет?» - это лишь половина проблемы разработки программного обеспечения.

Также кажется, что было бы проще скомпилировать код на языке, который интерпретируется естественно, чем добавить интерпретатор к языку, который компилируется по умолчанию.

2
ответ дан 30 November 2019 в 05:42
поделиться

REPL . Не стучите, пока не попробуете. :)

2
ответ дан 30 November 2019 в 05:42
поделиться

По дизайну.

Авторы хотели, чтобы они могли писать сценарии.

Python компилируется при первом запуске, хотя

1
ответ дан 30 November 2019 в 05:42
поделиться

Несколько причин:

  • более быстрый цикл разработки, write-test vs write-compile-link-test
  • проще организовать для динамического поведения ( отражение, метапрограммирование)
  • делает всю систему переносимой (просто перекомпилируйте базовый код C, и вы можете перейти на новую платформу)

Подумайте, что бы произошло, если бы система не интерпретировалась . Допустим, вы использовали перевод на C в качестве механизма. Скомпилированный код должен периодически проверять, не был ли он заменен метапрограммированием. Аналогичная ситуация возникает с функциями типа eval () . В этих случаях ему придется снова запустить компилятор, что является невероятно медленным процессом, или в любом случае потребуется также интерпретатор во время выполнения.

Единственная альтернатива здесь - JIT-компилятор. Эти системы очень сложны и изощрены и имеют даже большие следы времени выполнения, чем все другие альтернативы. Они запускаются очень медленно, что делает их непрактичными для написания сценариев. Вы когда-нибудь видели сценарий Java? У меня нет.

Итак, у вас есть два варианта:

  • все недостатки как компилятора, так и интерпретатора
  • только недостатки интерпретатора

Неудивительно, что обычно первичная реализация просто идет со вторым выбором. Вполне возможно, что когда-нибудь мы увидим появление вторичных реализаций, таких как компиляторы. Ruby 1.9 и Python имеют виртуальные машины с байт-кодом; там ½ пути. Компилятор может нацеливаться только на нединамический код или может иметь различные уровни поддержки языка, декларируемые как параметры. Но поскольку это не может быть основной реализацией, он представляет собой большой объем работы с очень незначительной выгодой. В Ruby уже есть 200 000 строк C ...

Я полагаю, я должен добавить, что всегда можно добавить скомпилированное расширение C (или, с некоторыми усилиями, любого другого языка). Итак, допустим, у вас есть медленная числовая операция. Если вы добавите, скажем, Array # newOp с реализацией C, вы получите ускорение, программа останется в Ruby (или чем-то еще), а ваша среда получит новый метод экземпляра. Выигрывают все! Таким образом, уменьшается потребность в проблемной вторичной реализации.

скажем Array # newOp с реализацией C, тогда вы получите ускорение, программа останется в Ruby (или чем-то еще), а ваша среда получит новый метод экземпляра. Выигрывают все! Таким образом, уменьшается потребность в проблемной вторичной реализации.

скажем Array # newOp с реализацией C, тогда вы получите ускорение, программа останется в Ruby (или чем-то еще), а ваша среда получит новый метод экземпляра. Выигрывают все! Таким образом, уменьшается потребность в проблемной вторичной реализации.

32
ответ дан 30 November 2019 в 05:42
поделиться

Производительность необработанных вычислений, вероятно, не является целью большинства интерпретируемых языков. Интерпретируемые языки обычно больше заботятся о производительности программиста, чем о чистой скорости. В большинстве случаев эти языки достаточно быстры для задач, для решения которых они были разработаны.

Учитывая это, и что почти единственными преимуществами компилятора являются проверка типов (что трудно сделать на динамическом языке) и скорость, нет особого стимула писать компиляторы для большинства интерпретируемых языков.

1
ответ дан 30 November 2019 в 05:42
поделиться

Компиляция Ruby по крайней мере, как известно, сложна. Я работаю над одним из них, и как часть этого я написал сообщение в блоге , в котором перечисляются некоторые из проблем здесь .

В частности, Ruby страдает от очень нечеткой (т. Е. Несуществующей) границы между фазами «чтения» и «выполнения» программы, что затрудняет ее эффективную компиляцию. Вы можете просто имитировать то, что делает интерпретатор, но тогда вы не увидите большого ускорения, так что это не стоит усилий. Если вы хотите скомпилировать его эффективно, вы столкнетесь с множеством дополнительных сложностей, чтобы справиться с экстремальным уровнем динамизма в Ruby.

Хорошая новость заключается в том, что существуют методы для преодоления этого. Self, Smalltalk и Lisp / Scheme довольно успешно справились с большинством тех же проблем. Но нужно время, чтобы разобраться в нем и понять, как заставить его работать с Ruby. Не помогает и то, что у Ruby очень запутанная грамматика.

1
ответ дан 30 November 2019 в 05:42
поделиться