В случае, если N
априорно не фиксируется:
for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
Я бы написал это на движке приложений Google (python), потому что:
Если бы я реализовал его на PHP, я бы
Это страница, с которой вы будете отправлять сообщения пользователю. С этой страницы вы отправите сообщение в 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
Код будет выглядеть что-то вроде этого:
но может и нет (из-за более медленного запуска и большего объема памяти), особенно когда типы также должны быть выведены или специализированы как часть генерации кода. Генерировать машинный код без вывода типа или специализации легко, если вы этого хотите, например freeze сделает это за вас, но на самом деле он не дает преимуществ, которые приписывают ему «фетишисты машинного кода». Например, вместо крошечного "hello world" .pyc
вы получаете исполняемый двоичный файл размером от 1,5 до 2 МБ - особого смысла нет! -). Этот исполняемый файл является автономным и распространяется как таковой, но он будет работать только в очень узком диапазоне операционных систем и архитектур ЦП, поэтому в большинстве случаев компромиссы весьма сомнительны. И время, необходимое для подготовки исполняемого файла, действительно довольно велико,
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.
Я думаю, что главная причина интерпретируемых языков - это переносимость. Как программист, вы можете написать код, который будет работать в интерпретаторе, а не в конкретной ОС. Таким образом, ваши программы ведут себя более единообразно на разных платформах (больше, чем на скомпилированных языках). Еще одно преимущество, о котором я могу думать, заключается в том, что легче иметь систему динамических типов в интерпретируемом языке. Я думаю, что создатели языка думали о том, чтобы создать язык, на котором программисты могут быть более продуктивными благодаря автоматическому управлению памятью, системе динамических типов и метапрограммированию, превосходящему любую потерю производительности из-за интерпретируемого языка. Если вас беспокоит производительность, вы всегда можете скомпилировать язык в машинный код, используя такой метод, как JIT-компиляция.
Ну, разве не одна из сильных сторон этих языков в том, что на них так легко скрипты? Их бы не было, если бы они были скомпилированы. С другой стороны, динамические языки легче интерпретировать, чем компилировать.
Сегодня больше нет четкого различия между «скомпилированными» и «интерпретируемыми» языками. На самом деле Python компилируется так же, как и Java, с единственными отличиями:
В 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 до 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]
На компилируемом языке цикл, в который вы попадаете при создании программного обеспечения, следующий:
Интерпретируемые языки как правило, быстрее создавать что-то, потому что вы можете вырезать второй шаг этого процесса (и когда вы имеете дело с большой системой, где время компиляции может составлять более двух минут, второй шаг может добавить значительное количество времени) .
Это не обязательно та причина, по которой разработчики python | ruby думали об этом, но имейте в виду, что «Насколько эффективно машина это выполняет?» - это лишь половина проблемы разработки программного обеспечения.
Также кажется, что было бы проще скомпилировать код на языке, который интерпретируется естественно, чем добавить интерпретатор к языку, который компилируется по умолчанию.
По дизайну.
Авторы хотели, чтобы они могли писать сценарии.
Python компилируется при первом запуске, хотя
Несколько причин:
Подумайте, что бы произошло, если бы система не интерпретировалась . Допустим, вы использовали перевод на 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 (или чем-то еще), а ваша среда получит новый метод экземпляра. Выигрывают все! Таким образом, уменьшается потребность в проблемной вторичной реализации. Производительность необработанных вычислений, вероятно, не является целью большинства интерпретируемых языков. Интерпретируемые языки обычно больше заботятся о производительности программиста, чем о чистой скорости. В большинстве случаев эти языки достаточно быстры для задач, для решения которых они были разработаны.
Учитывая это, и что почти единственными преимуществами компилятора являются проверка типов (что трудно сделать на динамическом языке) и скорость, нет особого стимула писать компиляторы для большинства интерпретируемых языков.
Компиляция Ruby по крайней мере, как известно, сложна. Я работаю над одним из них, и как часть этого я написал сообщение в блоге , в котором перечисляются некоторые из проблем здесь .
В частности, Ruby страдает от очень нечеткой (т. Е. Несуществующей) границы между фазами «чтения» и «выполнения» программы, что затрудняет ее эффективную компиляцию. Вы можете просто имитировать то, что делает интерпретатор, но тогда вы не увидите большого ускорения, так что это не стоит усилий. Если вы хотите скомпилировать его эффективно, вы столкнетесь с множеством дополнительных сложностей, чтобы справиться с экстремальным уровнем динамизма в Ruby.
Хорошая новость заключается в том, что существуют методы для преодоления этого. Self, Smalltalk и Lisp / Scheme довольно успешно справились с большинством тех же проблем. Но нужно время, чтобы разобраться в нем и понять, как заставить его работать с Ruby. Не помогает и то, что у Ruby очень запутанная грамматика.