在Moose中,通过对象的内部哈希直接访问成员变量是否安全?

use*_*481 4 perl moose

Moose对象似乎是带有成员变量作为条目的祝福hashrefs.使用哈希语法访问成员是否安全?我想要的只是获取/设置成员变量的简单能力,但我发现perl生成的访问器的速度对于我的应用程序来说是不可接受的,直到我考虑在非驼鹿OO中重写它.是的,我知道优化是一种可以判处死刑的罪行,但我有一个十亿+行文件并添加一个简单的行计数器变量可以增加十亿+函数调用,这可以在一次运行中增加几小时.

显示慢度(100x)的示例:

package Bullwinkle;
use strict;
use warnings;
use Moose;

has 'x' => (is => 'rw', default => 0);

# counter is also slow
has 'counter' => (
    traits  => ['Counter'],
    is      => 'ro',
    isa     => 'Num',
    default => 0,
    handles => {
        inc_counter   => 'inc',
    },
);

package main;
use strict;
use warnings;
use Benchmark qw/timethese cmpthese/;

my $bull = Bullwinkle->new();
my $hash = { x => 0 };

cmpthese(-1,{ 
    bull => sub{
        $bull->x(1 + $bull->x());
    },
    bull_direct => sub{
        ++$bull->{x}
    },
    bull_counter => sub{
        $bull->inc_counter();
    },
    hash => sub{
        ++$hash->{x}
    },
});
Run Code Online (Sandbox Code Playgroud)
  
                   Rate         bull bull_counter         hash  bull_direct
bull           983040/s           --         -28%         -91%         -92%
bull_counter  1362629/s          39%           --         -88%         -88%
hash         11251965/s        1045%         726%           --          -3%
bull_direct  11650844/s        1085%         755%           4%           --

bri*_*foy 14

我会说打破封装是不安全的,不管是不是.

请注意,您的bull测试速度不会慢100倍.请记住,它使用了两次访问器.就在信封的背面,它从每秒1,000,000次运行到每秒2,000,000次访问.与哈希相比,这使得它大约为6倍.添加一堆这些减速并且它可以加起来.

但是,我不认为穆斯是那里的问题.当我尝试使用非Moose类来做同样的事情时,结果并没有那么好.看起来大多数减速只是来自正常的面向对象的方法调用.使用非驼鹿和驼鹿类别之间的差异inc_counter大约为2倍.

基准是非常棘手的事情.您真的需要努力梳理不同的部件,并确保您测试适当的基本情况.当你得到狂野的数字时,你应该从怀疑论者开始并调整一下,直到它们不那么狂野.例如,即使Moose很慢,我也不认为如果你推测它很慢的话就会使用它.稍微慢一点,订单或数量是另一回事.


我对基准测试也很好奇,我想尝试一下make_immutable.这是我在运行Lion的Mac Pro上使用Moose-2.0403的默认Perl5.14.2的结果.Bull是你的原始代码,Rocky使用make_immutable,而Natasha是非Moose类,它做同样的事情:

                      Rate  bull rocky natasha bull_counter rocky_counter natasha_x rocky_x bull_x natasha_counter rocky_direct bull_direct natasha_direct hash
bull              728177/s    --   -6%    -17%         -42%          -43%      -65%    -66%   -67%            -71%         -93%        -94%           -94% -95%
rocky             771011/s    6%    --    -12%         -39%          -39%      -63%    -64%   -65%            -70%         -93%        -93%           -94% -95%
natasha           877713/s   21%   14%      --         -30%          -31%      -58%    -59%   -60%            -66%         -92%        -92%           -93% -94%
bull_counter     1260308/s   73%   63%     44%           --           -1%      -40%    -42%   -42%            -51%         -88%        -89%           -89% -91%
rocky_counter    1274310/s   75%   65%     45%           1%            --      -39%    -41%   -42%            -50%         -88%        -89%           -89% -91%
natasha_x        2105717/s  189%  173%    140%          67%           65%        --     -3%    -4%            -17%         -81%        -81%           -82% -85%
rocky_x          2163925/s  197%  181%    147%          72%           70%        3%      --    -1%            -15%         -80%        -81%           -82% -85%
bull_x           2184533/s  200%  183%    149%          73%           71%        4%      1%     --            -14%         -80%        -80%           -82% -85%
natasha_counter  2548621/s  250%  231%    190%         102%          100%       21%     18%    17%              --         -77%        -77%           -79% -82%
rocky_direct    10901037/s 1397% 1314%   1142%         765%          755%      418%    404%   399%            328%           --         -3%            -9% -24%
bull_direct     11202734/s 1438% 1353%   1176%         789%          779%      432%    418%   413%            340%           3%          --            -6% -21%
natasha_direct  11939231/s 1540% 1449%   1260%         847%          837%      467%    452%   447%            368%          10%          7%             -- -16%
hash            14252488/s 1857% 1749%   1524%        1031%         1018%      577%    559%   552%            459%          31%         27%            19%   --
Run Code Online (Sandbox Code Playgroud)

这是我的计划:

#!/Users/brian/bin/perls/perl5.14.2
use v5.10.1;
use strict;
use warnings;

use Benchmark qw/timethese cmpthese/;

package Bullwinkle {
    use strict;
    use warnings;
    use Moose;

    has 'x' => (is => 'rw', default => 0);

    # counter is also slow
    has 'counter' => (
        traits  => ['Counter'],
        is      => 'ro',
        isa     => 'Num',
        default => 0,
        handles => {
            inc_counter   => 'inc',
        },
    );
    }

package Rocky {
    use strict;
    use warnings;
    use Moose;

    has 'x' => (is => 'rw', default => 0);

    # counter is also slow
    has 'counter' => (
        traits  => ['Counter'],
        is      => 'ro',
        isa     => 'Num',
        default => 0,
        handles => {
            inc_counter   => 'inc',
        },
    );

    __PACKAGE__->meta->make_immutable;
    }

package Natasha {
    use strict;
    use warnings;

    sub new { bless { 'x' => 0 }, $_[0] }
    sub inc_counter { $_[0]->{x} += 1 }
    sub x           { 
        if( defined $_[1] ) { $_[0]->{x} = $_[1] }
        else                { $_[0]->{x} }
        }
    }

my $bull    = Bullwinkle->new;
my $rocky   = Rocky->new;
my $natasha = Natasha->new;

my $hash  = { 'x' => 0 };

cmpthese(-1,{ 
    bull          => sub { $bull->x(1 + $bull->x )   },
    bull_x        => sub { $bull->x                  },
    bull_direct   => sub { ++$bull->{'x'}            },
    bull_counter  => sub { $bull->inc_counter        },

    rocky         => sub { $rocky->x(1 + $rocky->x ) },
    rocky_x       => sub { $rocky->x                 },
    rocky_direct  => sub { ++$rocky->{'x'}           },
    rocky_counter => sub { $rocky->inc_counter       },

    natasha         => sub { $natasha->x(1 + $natasha->x ) },
    natasha_x       => sub { $natasha->x                   },
    natasha_direct  => sub { ++$natasha->{'x'}             },
    natasha_counter => sub { $natasha->inc_counter         },

    hash          => sub { ++$hash->{'x'}            },
});
Run Code Online (Sandbox Code Playgroud)