Perl: очевидное-невероятное
Mar. 22nd, 2006 05:21 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Оказывается, код, содержащий меньшее количество my-переменных, может выполняться в разы дольше, чем код с большим их количеством.
Пример под катом:
Первый код работает 22 cекунды против 6 секунд второго кода, то есть, почти в 4 раза больше.
>time perl fields_hashes.pl
0.01user 0.00system 0:21.48elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
>time perl fields_hashes.pl
0.01user 0.01system 0:05.54elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
Кстати, варианты с
Такая вот арифметика - видимо, связанная с особенностями размещения памяти и логикой построения внутренних структур.
Update: Сделал ещё варианты с использованием blessed массивов и скаляров в качестве классов, получились предсказуемые результаты. С массивами быстрее, чем с хэшами (4.79с.). И медленнее, чем со скалярами (3.62с., даже при том, что я ввёл в конструкторе my-переменную ind, которую и bless`ил).
Что ещё интересно, с тривиальным эмулятором обращений к классам вида (пример для blessed скаляров):
, "массивный" вариант увеличивает время выполнения всего на 0.86с., что ненамного меньше "хэшовых" 1.2с (вариант с присваиванием через
Мораль: разница микроскопическая, но есть, а пользоваться надо любым удобным способом без попыток излишних оптимизаций, как завещает нам великий Wall.
Пример под катом:
- Первый код
#!/usr/bin/perl
use strict;
package Aa;
sub new {
my $class = shift;
return bless { @_ }, $class;
}
package main;
my @aaa = map( Aa->new( ind => $_ ), ( 1 .. 1000000 ) ); - Второй код
#!/usr/bin/perl
use strict;
package Aa;
sub new {
my $class = shift;
my $self = bless { @_ }, $class;
return $self;
}
package main;
my @aaa = map( Aa->new( ind => $_ ), ( 1 .. 1000000 ) );
Первый код работает 22 cекунды против 6 секунд второго кода, то есть, почти в 4 раза больше.
>time perl fields_hashes.pl
0.01user 0.00system 0:21.48elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
>time perl fields_hashes.pl
0.01user 0.01system 0:05.54elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
Кстати, варианты с
use fields qw(ind);
работают: - 8.78c. с конструктором вида:
my $class = shift;
my $self = fields::new( $class );
$self->{ ind } = $_[1];
return $self; - 12.25c. с конструктором вида:
my $class = shift;
my $self = fields::new( $class );
for( my $i = 0; $i < $#_; $i += 2 ) {
$self->{ $_[ $i ] } = $_[ $i+1 ];
}
return $self; - 14.51c. с конструктором вида:
my $class = shift;
my $self = fields::new( $class );
%$self = ( %$self, @_ );
return $self; - 15.62c. с конструктором вида:
my $class = shift;
my $self = fields::new( $class );
while ( my ( $key, $val ) = splice( @_, 0, 2) ) {
$self->{ $key } = $val;
}
return $self; - и 16.32c. с конструктором вида:
my $class = shift;
my $self = fields::new( $class );
my $ary = { @_ };
map( $self->{ $_ } = $ary->{ $_ }, keys %$ary );
return $self;
Такая вот арифметика - видимо, связанная с особенностями размещения памяти и логикой построения внутренних структур.
Update: Сделал ещё варианты с использованием blessed массивов и скаляров в качестве классов, получились предсказуемые результаты. С массивами быстрее, чем с хэшами (4.79с.). И медленнее, чем со скалярами (3.62с., даже при том, что я ввёл в конструкторе my-переменную ind, которую и bless`ил).
Что ещё интересно, с тривиальным эмулятором обращений к классам вида (пример для blessed скаляров):
my $sum = 0;
$$_++ for ( @aaa );
$sum += $$_ for ( @aaa );
print "$sum\n";
, "массивный" вариант увеличивает время выполнения всего на 0.86с., что ненамного меньше "хэшовых" 1.2с (вариант с присваиванием через
$self->{ ind } = $_[1];
), и также ненамного больше скалярных 0.55с. (как в приведённом выше примере обращений).Мораль: разница микроскопическая, но есть, а пользоваться надо любым удобным способом без попыток излишних оптимизаций, как завещает нам великий Wall.
no subject
Date: 2006-03-22 04:52 pm (UTC)no subject
Date: 2006-03-22 09:39 pm (UTC)no subject
Date: 2006-03-22 10:26 pm (UTC)я бы счел, что первый код будет быстрее =)
no subject
Date: 2006-03-23 10:21 am (UTC)no subject
Date: 2006-03-23 11:41 am (UTC)return bless { }, $class;
и соответствующий вариант с использованием$self
. Результаты не менее интересный.Вот они с закомментированными и разкомментированными операциями между =pod и =cut:
my @aaa = map( Aa->new( ind => $_ ), ( 1 .. 1000000 ) );
print_elapsed();
#=pod
my $sum = 0;
$_->{ind}++ for ( @aaa );
$sum += $_->{ind} for ( @aaa );
print "$sum\n";
print_elapsed();
#=cut
return $self; с операциями:
vvv---
Elapsed: 3.269316-3.269316
1000000
Elapsed: 4.674113-1.404797
^^^---
Elapsed: 5.456588-0.782475
0.01user 0.00system 0:05.81elapsed 0%CPU (0avgtext+0avgdata 8560maxresident)k
0inputs+0outputs (540major+0minor)pagefaults 0swaps
return bless...; с операциями:
vvv---
Elapsed: 19.599274-19.599274
1000000
Elapsed: 21.036108-1.436834
^^^---
Elapsed: 21.81942-0.783312000000002
0.01user 0.01system 0:22.17elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
return $self; без операций:
vvv---
Elapsed: 3.268335-3.268335
^^^---
Elapsed: 3.536281-0.267946
0.01user 0.00system 0:03.76elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
return bless...; без операций:
vvv---
Elapsed: 19.569891-19.569891
^^^---
Elapsed: 19.83925-0.269359000000001
0.01user 0.00system 0:20.07elapsed 0%CPU (0avgtext+0avgdata 8576maxresident)k
0inputs+0outputs (541major+0minor)pagefaults 0swaps
Подозреваю, что указанные результаты - вследствие сложности жизни простых realloc`ов и/или размещения данных на стеке в условиях большого использования памяти.