首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perl的unpack()比substr()快吗?

Perl的unpack()比substr()快吗?
EN

Stack Overflow用户
提问于 2009-07-05 00:55:17
回答 5查看 4.4K关注 0票数 16

有几次我读到unpack()substr()更快,特别是当子字符串的数量增加时。然而,这个基准表明情况并非如此。是我的基准测试有缺陷,还是所谓的unpack()的性能优势是旧版本的Perl遗留下来的?

代码语言:javascript
复制
use strict;
use warnings;
use Benchmark;

my ($data, $format_string, $n_substrings);

my %methods = (
    unpack => sub { return unpack $format_string, $data },
    substr => sub { return map {substr $data, $_, 1} 0 .. $n_substrings - 1 },
);

for my $exp (1 .. 5){
    $n_substrings = 10 ** $exp;
    print $n_substrings, "\n";
    $format_string = 'a1' x $n_substrings;
    $data          =   9  x $n_substrings;
    Benchmark::cmpthese -2, \%methods;
}

输出(在Windows上):

代码语言:javascript
复制
10
           Rate unpack substr
unpack 131588/s     --   -52%
substr 276802/s   110%     --
100
          Rate unpack substr
unpack 13660/s     --   -57%
substr 31636/s   132%     --
1000
         Rate unpack substr
unpack 1027/s     --   -68%
substr 3166/s   208%     --
10000
         Rate unpack substr
unpack 84.4/s     --   -74%
substr  322/s   281%     --
100000
         Rate unpack substr
unpack 5.46/s     --   -82%
substr 30.1/s   452%     --

正如一些答案所指出的,unpack()在Windows上表现不佳。以下是solaris机器上的输出--虽然不是那么决定性,但substr()仍然赢得了这场比赛:

代码语言:javascript
复制
10
           Rate unpack substr
unpack 202274/s     --    -4%
substr 210818/s     4%     --
100
          Rate unpack substr
unpack 22015/s     --    -9%
substr 24322/s    10%     --
1000
         Rate unpack substr
unpack 2259/s     --    -9%
substr 2481/s    10%     --
10000
        Rate unpack substr
unpack 225/s     --    -9%
substr 247/s     9%     --
100000
         Rate unpack substr
unpack 22.0/s     --   -10%
substr 24.4/s    11%     --
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-10-19 17:43:41

自从提出这个问题以来,我已经在不同的条件下对substrunpack进行了几次基准测试。以下是我学到的一些东西:

  • 不会以在无效上下文中调用Perl函数的方式设置基准测试(正如我在原始问题中所做的那样;请参阅dlowe提供的有用的响应)。
  • 如果您使用的substr涉及循环(例如,迭代列位置列表),unpack总是更快。然而,在这种情况下,substr的明显缓慢是由于循环的开销,而不是substr本身。
  • 如果只需要几个字段,substr通常更快或者与unpack一样快。需要更多的字段,unpack和等效数量的substr调用之间的正面比较不会随着字段数量的增加而变化很大:在同一个substr上,这两种方法都会变慢,不同的操作系统可能会有所不同。在我的Windows XP机器上,每当需要几个以上的字段时,unpack都略胜一筹。在我工作的地方,在我们的Solaris机器上,substr总是更快,甚至进入几百个字段。

底线:无论字段的数量如何,unpacksubstr的性能并不是一个很大的问题。使用任何产生最清晰代码的方法。但是,如果您发现自己在循环构造中使用substr,那么切换到unpack将会带来显著的速度提升。

票数 3
EN

Stack Overflow用户

发布于 2009-07-11 04:46:49

事实上,您的基准测试是有缺陷的,这是非常非常有趣的,但归根结底,您真正比较的是unpack和map可以丢弃列表的相对效率,因为benchmark::can ()是在void上下文中执行函数。

您的substr出现在顶部的原因是pp_ctl.c pp_mapwhile()中的这行代码:

代码语言:javascript
复制
if (items && gimme != G_VOID) {

例如,如果perl的map知道它在void上下文中被调用,它就会神奇地跳过一大堆工作(即为map的结果分配存储空间)!

(我对windows和上面看到的其他内存分配的预感是,基于windows的perl内存分配很糟糕,所以跳过分配会节省更多的成本--不过,我的预感是,我没有windows机器可玩。但实际的解包实现是简单的C代码,不同的窗口不应该有本质的区别。)

我有三种不同的解决方案来解决这个问题,并生成更公平的比较:

  1. 将列表分配给一个数组
  2. 循环遍历函数内部的列表,并返回
  3. 返回对列表的引用(隐藏空上下文)

这是我的%methods版本,包含所有三个版本:

代码语言:javascript
复制
my %methods = (
    unpack_assign => sub { my @foo = unpack $format_string, $data; return },
    unpack_loop => sub { for my $foo (unpack $format_string, $data) { } },
    unpack_return_ref => sub { return [ unpack $format_string, $data ] },
    unpack_return_array => sub { return unpack $format_string, $data },

    substr_assign => sub { my @foo = map {substr $data, $_, 1} 0 .. ($n_substrings - 1) },
    substr_loop => sub { for my $foo ( map {substr $data, $_, 1} 0 .. ($n_substrings - 1)) { } },
    substr_return_ref => sub { return [ map {substr $data, $_, 1} 0 .. ($n_substrings - 1) ] },
    substr_return_array => sub { return map { substr $data, $_, 1} 0 .. ($n_substrings - 1) },
);

我的结果是:

代码语言:javascript
复制
$ perl -v

This is perl, v5.10.0 built for x86_64-linux-gnu-thread-multi

$ perl foo.pl
10
                        Rate substr_assign substr_return_ref substr_loop unpack_assign unpack_return_ref unpack_loop unpack_return_array substr_return_array
substr_assign       101915/s            --              -20%        -21%          -28%              -51%        -51%                -65%                -69%
substr_return_ref   127224/s           25%                --         -1%          -10%              -39%        -39%                -57%                -62%
substr_loop         128484/s           26%                1%          --           -9%              -38%        -39%                -56%                -61%
unpack_assign       141499/s           39%               11%         10%            --              -32%        -32%                -52%                -57%
unpack_return_ref   207144/s          103%               63%         61%           46%                --         -1%                -29%                -37%
unpack_loop         209520/s          106%               65%         63%           48%                1%          --                -28%                -37%
unpack_return_array 292713/s          187%              130%        128%          107%               41%         40%                  --                -12%
substr_return_array 330827/s          225%              160%        157%          134%               60%         58%                 13%                  --
100
                       Rate substr_assign substr_loop substr_return_ref unpack_assign unpack_return_ref unpack_loop unpack_return_array substr_return_array
substr_assign       11818/s            --        -25%              -25%          -26%              -53%        -55%                -63%                -70%
substr_loop         15677/s           33%          --               -0%           -2%              -38%        -40%                -51%                -60%
substr_return_ref   15752/s           33%          0%                --           -2%              -37%        -40%                -51%                -60%
unpack_assign       16061/s           36%          2%                2%            --              -36%        -39%                -50%                -59%
unpack_return_ref   25121/s          113%         60%               59%           56%                --         -4%                -22%                -35%
unpack_loop         26188/s          122%         67%               66%           63%                4%          --                -19%                -33%
unpack_return_array 32310/s          173%        106%              105%          101%               29%         23%                  --                -17%
substr_return_array 38910/s          229%        148%              147%          142%               55%         49%                 20%                  --
1000
                      Rate substr_assign substr_return_ref substr_loop unpack_assign unpack_return_ref unpack_loop unpack_return_array substr_return_array
substr_assign       1309/s            --              -23%        -25%          -28%              -52%        -54%                -62%                -67%
substr_return_ref   1709/s           31%                --         -3%           -6%              -38%        -41%                -51%                -57%
substr_loop         1756/s           34%                3%          --           -3%              -36%        -39%                -49%                -56%
unpack_assign       1815/s           39%                6%          3%            --              -34%        -37%                -48%                -55%
unpack_return_ref   2738/s          109%               60%         56%           51%                --         -5%                -21%                -32%
unpack_loop         2873/s          120%               68%         64%           58%                5%          --                -17%                -28%
unpack_return_array 3470/s          165%              103%         98%           91%               27%         21%                  --                -14%
substr_return_array 4015/s          207%              135%        129%          121%               47%         40%                 16%                  --
10000
                     Rate substr_assign substr_return_ref substr_loop unpack_assign unpack_return_ref unpack_loop unpack_return_array substr_return_array
substr_assign       131/s            --              -23%        -27%          -28%              -52%        -55%                -63%                -67%
substr_return_ref   171/s           30%                --         -5%           -6%              -38%        -42%                -52%                -57%
substr_loop         179/s           37%                5%          --           -1%              -35%        -39%                -50%                -55%
unpack_assign       181/s           38%                6%          1%            --              -34%        -38%                -49%                -55%
unpack_return_ref   274/s          109%               60%         53%           51%                --         -6%                -23%                -32%
unpack_loop         293/s          123%               71%         63%           62%                7%          --                -18%                -27%
unpack_return_array 356/s          171%              108%         98%           96%               30%         21%                  --                -11%
substr_return_array 400/s          205%              134%        123%          121%               46%         37%                 13%                  --
100000
                      Rate substr_assign substr_return_ref substr_loop unpack_assign unpack_return_ref unpack_loop unpack_return_array substr_return_array
substr_assign       13.0/s            --              -22%        -26%          -29%              -51%        -55%                -63%                -67%
substr_return_ref   16.7/s           29%                --         -5%           -8%              -37%        -43%                -52%                -58%
substr_loop         17.6/s           36%                5%          --           -3%              -33%        -40%                -50%                -56%
unpack_assign       18.2/s           40%                9%          3%            --              -31%        -37%                -48%                -54%
unpack_return_ref   26.4/s          103%               58%         50%           45%                --         -9%                -25%                -34%
unpack_loop         29.1/s          124%               74%         65%           60%               10%          --                -17%                -27%
unpack_return_array 35.1/s          170%              110%         99%           93%               33%         20%                  --                -12%
substr_return_array 39.7/s          206%              137%        125%          118%               50%         36%                 13%                  --

所以回到最初的问题:“unpack()比substr()快吗?”答:对于这种类型的应用程序,总是如此--除非您不关心返回值;)

票数 21
EN

Stack Overflow用户

发布于 2009-07-05 06:43:45

这项测试没有缺陷,但它是有偏差的。如果您所需要做的只是从字符串中提取一个相当简单的子字符串,则substr更好,但仅此而已。例如,即使是这个简单的任务也不能使用substr轻松完成:

代码语言:javascript
复制
$foo = '123foo456789bar89012';
my ($t1,$t2,$t3,$t4,$t5) = unpack("A3A3A6A3A5",$foo);

这就是substr和unpack之间的显著区别所在。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1083269

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档