Классы, обьекты и accessors - небольшой benchmark

Привет всем

Начал для себя искать модуль который можна бы использовать как генератор accessors (простой уже нашел), ну еще один на все остальные навороты :)

и вот на этапе тестирования скорости как бы немного удивили такие результаты

./test.pl
use Accessor;
timethis 100000: 5 wallclock secs ( 4.00 usr + 0.12 sys = 4.12 CPU) @ 24271.84/s (n=100000)
use Object::InsideOut;
timethis 100000: 54 wallclock secs (47.45 usr + 0.13 sys = 47.58 CPU) @ 2101.72/s (n=100000)
use MethodMaker;
timethis 100000: 2 wallclock secs ( 1.81 usr + 0.01 sys = 1.82 CPU) @ 54945.05/s (n=100000)

Object::InsideOut на удивление показал слишком плохие результаты
возможно я немного неправильно тестирую
хотелось бы узнать вашу точку зрения

test.pl

#!/usr/bin/perl
use Benchmark qw(:all);
my $count = 100000;
my $Accessor = sub {
require ClassTest::Accessor;
my $o = ClassTest::Accessor->new();
$o->test('test');
$o->test();
};
my $ObjectInsideOut = sub {
require ClassTest::ObjectInsideOut;
my $o = ClassTest::ObjectInsideOut->new();
$o->test('test');
$o->test();
};
my $MethodMaker = sub {
require ClassTest::MethodMaker;
my $o = ClassTest::MethodMaker->new();
$o->test('test');
$o->test();
};
clearallcache();
print "use Accessor;\n";
timethis( $count, $Accessor );
clearallcache();
print "use Object::InsideOut;\n";
timethis( $count, $ObjectInsideOut );
clearallcache();
print "use MethodMaker;\n";
timethis( $count, $MethodMaker );
clearallcache();

ClassTest/Accessor.pm

package ClassTest::Accessor;
use base qw( Class::Accessor );
use strict;
use warnings;
use Class::Accessor;
__PACKAGE__->mk_accessors( qw( test ) );
our $VERSION = '0.01';
1;

ClassTest/MethodMaker.pm

package ClassTest::MethodMaker;
use strict;
use warnings;
use Class::MethodMaker
[ scalar => [qw/ test /],
  new    => [qw/ new  /],
];
our $VERSION = '0.01';
1;

ClassTest/ObjectInsideOut.pm

package ClassTest::ObjectInsideOut;
use strict;
use warnings;
use Object::InsideOut;
my @test :Field :Accessor(test);
our $VERSION = '0.01';
1;

В вашей задаче

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

Спасибо, было интересно.

./test.pl
create Accessor;
timethis 100000: 2 wallclock secs ( 0.84 usr + 0.01 sys = 0.85 CPU) @ 117431.19/s (n=100000)
create Object::InsideOut;
timethis 100000: 26 wallclock secs (25.26 usr + 0.74 sys = 26.00 CPU) @ 3846.15/s (n=100000)
create MethodMaker;
timethis 100000: -1 wallclock secs ( 0.63 usr + 0.00 sys = 0.63 CPU) @ 158024.69/s (n=100000)

use Accessor;
timethis 100000: 0 wallclock secs ( 1.22 usr + 0.01 sys = 1.23 CPU) @ 81528.66/s (n=100000)
use Object::InsideOut;
timethis 100000: 1 wallclock secs ( 0.48 usr + 0.00 sys = 0.48 CPU) @ 206451.61/s (n=100000)
use MethodMaker;
timethis 100000: 1 wallclock secs ( 0.57 usr + 0.00 sys = 0.57 CPU) @ 175342.47/s (n=100000)

Вот мой вариант кода:

#!/usr/bin/perl
use Benchmark qw(:all);
my $count = 100000;
require ClassTest::Accessor;
my $oa = ClassTest::Accessor->new();
require ClassTest::ObjectInsideOut;
my $oi = ClassTest::ObjectInsideOut->new();
require ClassTest::MethodMaker;
my $om = ClassTest::MethodMaker->new();
my $Accessor = sub {
$oa->test('test');
$oa->test();
};
my $dAccessor = sub {
my $o = ClassTest::Accessor->new();
};
my $ObjectInsideOut = sub {
$oi->test('test');
$oi->test();
};
my $dObjectInsideOut = sub {
my $o = ClassTest::ObjectInsideOut->new();
};
my $MethodMaker = sub {
$om->test('test');
$om->test();
};
my $dMethodMaker = sub {
my $o = ClassTest::MethodMaker->new();
};
clearallcache();
print "create Accessor;\n";
timethis( $count, $dAccessor );
clearallcache();
print "create Object::InsideOut;\n";
timethis( $count, $dObjectInsideOut );
clearallcache();
print "create MethodMaker;\n";
timethis( $count, $dMethodMaker );
clearallcache();
print "use Accessor;\n";
timethis( $count, $Accessor );
clearallcache();
print "use Object::InsideOut;\n";
timethis( $count, $ObjectInsideOut );
clearallcache();
print "use MethodMaker;\n";
timethis( $count, $MethodMaker );

выводы

о теперь вполне понятные результаты
вы более правильно провели тест ;)

Accessor (да и Accessor::Fast - смотри мой блог(1)) розочаровал
скорость маленькая как при создании обьекта так и при get/set
причем способ использования не весьма удобен и возможности скудные

А технологии insideout и hash-blessed (в лице Object::InsideOut и MethodMaker соответсвенно) теперь показали вполне закономерные результаты

при создании обьекта insideout проигрывает, зато при доступе есть отрыв, правда не сильно большой

думаю надо еще добавить для експеримента пару модулей
и перезапустить

1 - http://kiev.pm.org/node/203

PS: плохо что текст кода нельзя скрыть как спойлер или просто прикреплять - занимает много места :(

вот еще плюс

вот еще плюс парочку модулей потестил

./test2.pl
benchmark new()
Class::Accessor
timethis 200000: 3 wallclock secs ( 2.50 usr + 0.00 sys = 2.50 CPU) @ 80000.00/s (n=200000)
Class::MakeMethods::Standard::Hash
timethis 200000: 2 wallclock secs ( 1.83 usr + 0.00 sys = 1.83 CPU) @ 109289.62/s (n=200000)
Class::MethodMaker
timethis 200000: 1 wallclock secs ( 0.88 usr + 0.00 sys = 0.88 CPU) @ 227272.73/s (n=200000)
Object::InsideOut
timethis 200000: 94 wallclock secs (88.31 usr + 0.08 sys = 88.39 CPU) @ 2262.70/s (n=200000)
benchmark get/set
Class::Accessor
timethis 200000: 1 wallclock secs ( 1.73 usr + 0.00 sys = 1.73 CPU) @ 115606.94/s (n=200000)
Class::MakeMethods::Standard::Hash
timethis 200000: 1 wallclock secs ( 0.74 usr + 0.01 sys = 0.75 CPU) @ 266666.67/s (n=200000)
Class::Member::HASH
timethis 200000: 6 wallclock secs ( 5.91 usr + 0.00 sys = 5.91 CPU) @ 33840.95/s (n=200000)
Class::MethodMaker
timethis 200000: 1 wallclock secs ( 0.60 usr + 0.00 sys = 0.60 CPU) @ 333333.33/s (n=200000)
Object::InsideOut
timethis 200000: 1 wallclock secs ( 0.58 usr + 0.01 sys = 0.59 CPU) @ 338983.05/s (n=200000)

test2.pl

#!/usr/bin/perl
use Benchmark qw(:all);
require ClassTest::Accessor;
require ClassTest::MakeMethods;
require ClassTest::Member;
require ClassTest::MethodMaker;
require ClassTest::ObjectInsideOut;
my $count = 200000;
my $o_A     = ClassTest::Accessor->new();
my $o_MMs   = ClassTest::MakeMethods->new();
my $o_M     = ClassTest::Member->new();
my $o_MM    = ClassTest::MethodMaker->new();
my $o_IO    = ClassTest::ObjectInsideOut->new();
clearallcache();
print "benchmark new()\n";
print "Class::Accessor\n";
timethis( $count, sub { my $o = ClassTest::Accessor->new(); } );
clearallcache();
print "Class::MakeMethods::Standard::Hash\n";
timethis( $count, sub { my $o = ClassTest::MakeMethods->new(); } );
clearallcache();
#print "Class::Member::HASH\n";
#timethis( $count, sub { my $o = ClassTest::Member->new(); } );
clearallcache();
print "Class::MethodMaker\n";
timethis( $count, sub { my $o = ClassTest::MethodMaker->new(); } );
clearallcache();
print "Object::InsideOut\n";
timethis( $count, sub { my $o = ClassTest::ObjectInsideOut->new(); } );
clearallcache();
print "benchmark get/set\n";
print "Class::Accessor\n";
timethis( $count, sub { $o_A->test('test'); $o_A->test(); } );
clearallcache();
print "Class::MakeMethods::Standard::Hash\n";
timethis( $count, sub { $o_MMs->test('test'); $o_MMs->test(); } );
clearallcache();
print "Class::Member::HASH\n";
timethis( $count, sub { $o_M->test('test'); $o_M->test(); } );
clearallcache();
print "Class::MethodMaker\n";
timethis( $count, sub { $o_MM->test('test'); $o_MM->test(); } );
clearallcache();
print "Object::InsideOut\n";
timethis( $count, sub { $o_IO->test('test'); $o_IO->test(); } );
clearallcache();