Самый быстрый способ вызова подпрограммы

Насколько я знаю, в Perl мы можем вызвать подпрограмму из модуля, используя следующие методы:

  • Экспортировать подпрограмму foo , импортировать модуль, который имеет эту подпрограмму. Наконец, назовите его в своем скрипте perl.
  • Создайте Object этого модуля в вашем perl-скрипте, наконец, вызовите foo , используя этот Object .
  • Непосредственно вызовите foo , используя его путь, как этот myDir :: Module :: foo (); .

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

Благодарю.

2
nl ja de
У всех есть свое место. Вы не должны беспокоиться о скорости вызова - Perl работает быстро.
добавлено автор Borodin, источник
1,3 очень похоже, 2 - метод ООП, так что это совсем другой вид
добавлено автор Karthik T, источник
@ Krishna По моему мнению, я имел в виду, что разница между # 1 и # 3 по сути является ТОЛЬКО вопросом стиля, оба действительны, возможно, # 3 немного лучше. # 2 очень отличается и не может сравниться, поскольку одна и та же функция не может быть написана разумно в обоих стилях.
добавлено автор Karthik T, источник
Если вы хотите иметь подпрограмму в своем основном (или текущем) пространстве имен, создайте ее таким образом, чтобы сделать ее импортируемой (т. Е. С помощью Exporter )). Если, например, у него очень распространенное имя, и у вас есть несколько пакетов, у которых есть sub с этим именем, используйте третий метод. Он будет создавать более длинные линии, но будет легче обслуживаться для парня, который приходит после вас.
добавлено автор simbabque, источник
но, какой должна быть хорошая практика и быстрая среди всех трех?
добавлено автор Krishnachandra Sharma, источник
Так не должно быть никакого сравнения?
добавлено автор Krishnachandra Sharma, источник
@ Karthik Спасибо за ваши мудрые слова. :)
добавлено автор Krishnachandra Sharma, источник

2 ответы

Существует разница между самым быстрым и лучшим способом вызова кода в Perl.


Редактировать: см. Также ответ simbabques. Особенно он учитывает различия между # 1 и №3 и почему вы также должны использовать их.


# 1, # 3: вызовы функций

Ваши # 1 и # 3 идентичны: подпрограмма имеет уникальное имя в глобально видимом пространстве имен. Многие имена могут отображаться в одной подпрограмме через псевдонимы или импортировать модуль.

Если имя функции, которую вы вызываете, известно во время компиляции, суб будет разрешено во время компиляции. Это предполагает, что вы не спонтанно не переопределяете свои функции. Если точная функция известна только во время выполнения, это только хэш-поиск.

Существует три способа вызова функций:

foo(@args);
&foo(@args);
@_ = @args; goto &foo;

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

Номер два пропускает проверку protoype и предполагает, что вы знаете, что делаете. Это немного быстрее. Я думаю, что это неряшливый стиль.

Number three is a tail call. This returns from the current sub with the return value of foo. This is fast, as prototypes are ignored, and the current call stack frame can be reused. This isn't useful very often, and has ugly syntax. Inlining the code is about an order of magnitude faster (i.e. in Perl, we prefer loops over recursion ☹).

# 2: вызов метода

Гибкость OO достигает высокой производительности: поскольку тип объекта, которому вы вызываете сообщение, никогда не известен до времени выполнения, фактический метод может быть разрешен только во время выполнения.

This means that $foo->bar() looks up the function bar in the package that $foo was blessed into. If it can't be found there, it will be searched for in parent classes. This is slow. If you want to use OO, pay attention to shallow hierarchies (→ less lookups). Do also note that Perls default Method Resolution Order is unusual.

Обычно вы не можете вызвать вызов метода для вызова функции, даже если вы знаете тип.

Если $ foo , если из класса Foo , а Foo :: bar является sub, то Foo :: bar ($ foo) пропустит результат метода и может даже работать. Однако это прерывает инкапсуляцию и будет ломаться один раз, когда Foo подклассы. Кроме того, это не работает, если Foo не определяет bar , но метод был определен в родительском классе.

Я вообще поддерживаю объектную ориентацию, пока из тестов не станет ясно, что это не обеспечит требуемую производительность.

6
добавлено
Позор, мы не можем объединить наши ответы, я думаю, что оба вместе все это хорошо. ;-)
добавлено автор simbabque, источник
      
  • Экспортировать подпрограмму foo, импортировать модуль, который имеет эту подпрограмму. Наконец, назовите его в своем скрипте perl.
  •   

Чтобы сделать это, вы должны использовать Экспортер в модуле/ package , который реализует подпункт. Вы сообщаете модулю, что он будет экспортировать через @EXPORT_OK и @EXPORT . Если вы используете модуль, материал будет импортироваться в ваше текущее пространство имен во время компиляции. Следующие утверждения являются эквивалентными.

# This is the same...
use Module;
# ... as this

BEGIN {
  require Module;
  Module->import();
}

Вы хотите сделать это, если у вас есть материал, который вы собираетесь использовать в своем основном скрипте, или вы часто будете использовать его. Вот некоторые примеры: List :: Util , perlootut .

      
  • Непосредственно вызовите foo, используя его путь, например myDir :: Module :: foo ();.
  •   

На самом деле это не совсем его путь, а скорее его имя (пространство). Например, Data :: Dumper - это Dumper.pm , расположенный в папке Data , где-то в вашем каталоге lib . Но это не очень важно.

Основное отличие от первого подхода заключается в том, что вы исключаете часть импорта. Это полезно, если вы хотите создать что-то, что условно загружает определенные модули, или если вы находитесь в огромном (возможно, устаревшем) приложении и не хотите загрязнять пространство имен.

if ($order_has_some_condition) {
  require Very::Long::NameSpace::For::This::Condition::Module;
  Very::Long::NameSpace::For::This::Condition::Module::do_stuff_with_an_order($order);
}

Представьте, что этот фрагмент кода находится в унаследованном подразделении с линиями 2k, и много чего происходит, большинство из них никогда не вызывается в нашем случае. Мы не хотим использовать наш модуль, что делает его доступным для каждого из, возможно, 100 различных случаев, которые обрабатываются в этой огромной части кода. Вместо этого мы хотим только загрузить его, если нам это действительно нужно. Теперь мы требуем модуля и вызываем его sub напрямую, используя полное имя.

В завершении, как первый, так и третий способ имеют свои достоинства. Они оба должны существовать, и оба они должны использоваться, если это необходимо. В некоторых случаях это просто аромат, но в других имеет смысл принять решение. Второй подход OOp - это совсем другое.

Нет реальных различий в скорости, и, как сказал Бородин, Perl быстро развивается. Конечно, если вы не используете import , вам не нужно «платить» за импорт. В сценарии с 10 строками это не имеет значения. В устаревшем программном обеспечении с потенциально тысячами строк кодов и множестве случаев использования в одном огромном файле это имеет большое значение.

Надеюсь, это поможет вам решить.

4
добавлено
Modern::Perl
Modern::Perl
362 участник(ов)

Пожалуйста, представьтесь при добавлении в группу. Это необходимо во избежание спам-ботов. Ваше первое сообщение не должно быть ссылкой или репостом. Мы всегда рады нестандартным вопросам.

use Perl or die;
use Perl or die;
164 участник(ов)

Группа о языке Perl и обо всём что с ним связано.

pro.perl
pro.perl
22 участник(ов)

Язык программирования Perl