Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > компиляция и use


Автор: Сisa 23.12.2014, 15:11
Обычно в начале кода пишем все use.
Код

use URI::Escape;
...
if(defined $query){
... используем Escape
}else{
... модуль не нужен
}


А лучше ли такая запись:
Код

if(defined $query){
 use URI::Escape;
... и только из за того что есть $query используем Escape
}else{
... модуль не нужен
}

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


Автор: arto 23.12.2014, 16:24
если необходимо загружать модуль во rt, то используйте require (perldoc -f use).

Автор: Сisa 23.12.2014, 18:39
perldoc -f use  - там так мелко написано (в смысле по английски) что конкретно на вопрос ответа как бы и не нашел.

require URI::Escape;
меняет ситуацию по сравнению с use URI::Escape; т.е. загрузка модуля делаться теперь должна в момент вызова, 
и следует ли это понимать как полезное действие? Будет ли скрипт компилироваться, да и выполняться быстрее?
В примере подключается один модуль, но их же может быть более чем один.
Конечно можно делать замеры времени, вряд ли они покажут истину, да и сам вопрос скорее теоретический.

Автор: arto 23.12.2014, 18:42
непонятна ваша задача.

Автор: Сisa 23.12.2014, 21:58
Минимизировать время на выполнение perl-кода за счет экономии времени на компиляции и отсутствии излишнего подключения незадействованных модулей в случае если таковые модули в ходе выполнения скрипта не будут использованы.

Проще говоря - попытка ускорить скрипт smile

Автор: noize 23.12.2014, 23:07
Цитата

Проще говоря - попытка ускорить скрипт


1. Можно подгружать модуль через use не импортируя из него автоматически импортируемые данные. Для этого в своём коде пишете
Код

use Module ();  # <- скобки означают не импортировать данные

но это вряд ли сильно ускорит ваш скрипт. Если хочется найти узкие места, см. п. 2

2. Используйте https://metacpan.org/pod/Devel::NYTProf для профилирования своего скрипта. В итоге увидите, где у вас узкие места, которые долго выполняются.

Автор: Сisa 24.12.2014, 00:05
noize спасибо! 
Попробую освоить такую новинку.

но,
https://metacpan.org/pod/Devel::NYTProf :   ОПИСАНИЕ, п.11 :   Sub-мкс (100 нс) Разрешение на поддерживаемых системах

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

А почему не так: если модуль не нужен, и не загружается т.е. и не компилируется, то время на это не расходуется?
Разница в том что use всегда, даже если и записана в неиспользуемой ветке кода, загружает модуль,
а require подключает модуль только если записан в используемой части кода. Если модуль загружается, то он компилируется. А если не загружается, то вот и экономия времени и на загрузке и на компиляции модулей. 

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

Отсюда и возник вопрос: А лучше ли вторая запись из примера. 
Такая перестановка и правда вряд ли сильно ускорит скрипт, но сознание того что именно так правильно и так лучше ...?!?!?!?!?

Автор: odmink0 24.12.2014, 18:36
Лучше такая запись:

Код

use if defined $query, 'URI::Escape', qw(uri_escape);


Читайте Perl Advent Calendar, друзья! smile

http://perladvent.org/2014/2014-12-12.html

Автор: Pfailed 24.12.2014, 19:25
use загрузит модуль в любом случае на этапе компиляции, require -  во время выполнения. Не загружая ненужный модуль можно, конечно, сэкономить какие-то микросекунды и память. Но главный минус require  в отдельной ветке, на мой взгляд, это то, что при невозможности загрузить модуль скрипт свалится во время выполнения, что не всегда хорошо. Лучше уж пусть падает сразу при попытке запуска.

Поэтому обычно вначале скрипта загружают все нужные модули через use/require. А во время выполнения какие-то опциональные через eval{require}, без которых скрипт может работать. Например:
Код

my $socket_class = "IO::Socket::INET";
if (eval { require  IO::Socket::IP }) {
  $socket_class = "IO::Socket::IP";
}

my $sock = $socket_class->new()

Автор: alezzz 25.12.2014, 09:39
Код

use strict;
use warnings;

my $a = 'test';

if (1){
    require Data::Dumper;
    print Dumper $a;
}


почему я получаю варнинг 'Name "main::Dumper" used only once' и модуль не подключается?

Автор: Сisa 25.12.2014, 18:27
Perl Advent Calendar оказывается примерно в это же время, чуть раньше не считается, об этом тоже почему то написал  smile
use if defined $query, 'URI::Escape', qw(uri_escape); строка уже и не в начале кода, как все use,
но тем не менее это видимо и есть лучшее решение, хотя и так тоже неплохо:  if(defined $query){use URI::Escape;...}else{... модуль не нужен}, надеюсь форма записи не сильно меняет суть действия.

Pfailed спасибо! Если можно, то нужно! экономить микросекунды и память. Конечно мелочь, но все же принцип, что все возможные пути надо использовать, будет соблюден. А тестировать, что с use, что с require все равно ведь надо, чтобы скрипт не валится во время работы.
 

Автор: noize 26.12.2014, 16:13
Цитата

почему я получаю варнинг 'Name "main::Dumper" used only once' и модуль не подключается?

модуль подключается. Но require скорее всего не делает Module->import автоматом в отличие от use.

Добавлено через 1 минуту и 17 секунд
Сisa, что у вас там за приложение такое, для которого необходимо экономить ресурсы на старте? Perl - это не Java, он стартует почти мгновенно

Автор: alezzz 26.12.2014, 18:06
noize, похоже что так и есть, из документации не понял, т.к. английский далеко не идеальный, но на каком-то сайте примерно так и пишут, что не импортирует.
работает так:
Код

print Data::Dumper->Dumper($a);

но результат:
Код

$VAR1 = 'Data::Dumper';
$VAR2 = 'test';

тогда как при  use Data::Dumper результат:
Код

$VAR1 = 'test';


Автор: Pfailed 26.12.2014, 20:01
alezzz, Вот так сработает
Код

require Data::Dumper;
print Data::Dumper::Dumper($a);


или так

Код

require Data::Dumper;
Data::Dumper->import();
print Dumper($a);


При использовании "->" первым аргументом в функцию передаётся имя пакета, на котором был вызван метод, что собственно и видно.

А нижеследующее (Dumper без скобок )не работает. Но если использовать use, то работает. И тут дело в прототипах, которые perl может вычислить на этапе компиляции. Т.е. при использовании use perl на этапе компиляции узнал, что есть такая функция Dumper() и распарсил выражение "print Dumper $a", как "print(Dumper($a))". А при использовании require на этапе компиляции про Dumper() ничего неизвестно, поэтому perl распарсил это выражение как "print(Dumper $a)". Т.е. печать в файлхэндл Dumper.
Код

require Data::Dumper;
Data::Dumper->import();
print Dumper $a;

Автор: Сisa 29.12.2014, 22:16
"Сisa, что у вас там за приложение такое, для которого необходимо экономить ресурсы на старте? Perl - это не Java, он стартует почти мгновенно"

А что Java такой тормоз ? Значит следующим буду учить ассемблер       smile


Вот где то прочел, что может быть применено к моему вопросу:

"Я заостряю на этом внимание оттого, что слишком много начинающих программистов хватаются за эффективность даже в мелочах. Результат получается больше, сложнее и часто не без ошибок. Такие программы дольше писать, а работают они часто не сильно быстрее."

Просто ответ на вопрос мне был интересен. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)