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

时间:2012-04-11 08:59:34

标签: 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}
    },
});
  
                   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%           --

2 个答案:

答案 0 :(得分: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%   --

这是我的计划:

#!/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'}            },
});

答案 1 :(得分:0)

我认为这个基准测试还应该考虑以旧方式编写Perl类的“通常”方式:即使用$ self变量。

在这种情况下,公牛的好转率提高了3%,而且多头提高了12%。

以下是原始结果:

                      Rate tatiana  bull rocky natasha bull_counter rocky_counter tatiana_x tatiana_counter bull_x natasha_x rocky_x natasha_counter bull_direct hash tatiana_direct rocky_direct natasha_direct
tatiana           785983/s      --   -3%  -11%    -20%         -35%          -37%      -55%            -61%   -66%      -67%    -67%            -68%        -94% -95%           -95%         -95%           -95%
bull              811471/s      3%    --   -8%    -17%         -33%          -34%      -54%            -60%   -65%      -66%    -66%            -67%        -94% -94%           -94%         -94%           -95%                                 
rocky             882215/s     12%    9%    --    -10%         -27%          -29%      -50%            -56%   -62%      -63%    -63%            -64%        -93% -94%           -94%         -94%           -94%
natasha           983039/s     25%   21%   11%      --         -18%          -21%      -44%            -51%   -58%      -58%    -59%            -60%        -93% -93%           -93%         -93%           -94%
bull_counter     1203020/s     53%   48%   36%     22%           --           -3%      -31%            -40%   -48%      -49%    -50%            -50%        -91% -92%           -92%         -92%           -92%
rocky_counter    1238753/s     58%   53%   40%     26%           3%            --      -29%            -39%   -47%      -48%    -49%            -49%        -91% -91%           -91%         -91%           -92%
tatiana_x        1747627/s    122%  115%   98%     78%          45%           41%        --            -13%   -25%      -26%    -28%            -28%        -87% -88%           -88%         -88%           -89%
tatiana_counter  2016491/s    157%  148%  129%    105%          68%           63%       15%              --   -13%      -15%    -16%            -17%        -85% -86%           -86%         -86%           -87%
bull_x           2316929/s    195%  186%  163%    136%          93%           87%       33%             15%     --       -2%     -4%             -5%        -82% -84%           -84%         -84%           -85%
natasha_x        2360644/s    200%  191%  168%    140%          96%           91%       35%             17%     2%        --     -2%             -3%        -82% -83%           -84%         -84%           -85%
rocky_x          2414483/s    207%  198%  174%    146%         101%           95%       38%             20%     4%        2%      --             -1%        -82% -83%           -83%         -83%           -85%
natasha_counter  2429401/s    209%  199%  175%    147%         102%           96%       39%             20%     5%        3%      1%              --        -81% -83%           -83%         -83%           -85%
bull_direct     13107199/s   1568% 1515% 1386%   1233%         990%          958%      650%            550%   466%      455%    443%            440%          --  -8%           -10%         -10%           -17%
hash            14298763/s   1719% 1662% 1521%   1355%        1089%         1054%      718%            609%   517%      506%    492%            489%          9%   --            -2%          -2%           -10%
tatiana_direct  14563556/s   1753% 1695% 1551%   1381%        1111%         1076%      733%            622%   529%      517%    503%            499%         11%   2%             --          -0%            -8%
rocky_direct    14563556/s   1753% 1695% 1551%   1381%        1111%         1076%      733%            622%   529%      517%    503%            499%         11%   2%             0%           --            -8%
natasha_direct  15827561/s   1914% 1850% 1694%   1510%        1216%         1178%      806%            685%   583%      570%    556%            552%         21%  11%             9%           9%             --

新测试用例的差异(注意新的Tatiana类):

--- bench.old   2012-04-15 19:29:55.000000000 +0200
+++ bench.pl    2012-04-15 19:17:25.000000000 +0200
@@ -57,9 +57,26 @@
         }
     }

+package Tatiana {
+    use strict;
+    use warnings;
+
+    sub new { bless { 'x' => 0 }, $_[0] }
+    sub inc_counter { 
+        my $self = shift ;
+        $self->{x} += 1 
+    }
+    sub x           { 
+        my ($self,$arg) = @_ ;
+        if( defined $arg ) { $self->{x} = $arg }
+        else               { $self->{x} }
+        }
+    }
+
 my $bull    = Bullwinkle->new;
 my $rocky   = Rocky->new;
 my $natasha = Natasha->new;
+my $tatiana = Tatiana->new;

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

@@ -79,5 +96,10 @@
     natasha_direct  => sub { ++$natasha->{'x'}             },
     natasha_counter => sub { $natasha->inc_counter         },

+    tatiana         => sub { $tatiana->x(1 + $tatiana->x ) },
+    tatiana_x       => sub { $tatiana->x                   },
+    tatiana_direct  => sub { ++$tatiana->{'x'}             },
+    tatiana_counter => sub { $tatiana->inc_counter         },
+    
     hash          => sub { ++$hash->{'x'}            },
 });

希望这有帮助