繁体   English   中英

在Perl中访问字符串中的单个字符时,是否更快地子行或拆分为数组?

[英]When accessing individual characters in a string in Perl, is substr or splitting to an array faster?

我正在编写一个Perl脚本,我需要在其中循环遍历字符串的每个字符。 有很多字符串,每个字符串长100个字符(如果你想知道的话,它们是短的DNA序列)。

所以,它是更快地使用substr在一个时间,以提取每个字符之一,或者是它更快地split串入一个数组,然后迭代这个数组?

在我等待答案时,我想我会读到如何在Perl中对事物进行基准测试。

这实际上取决于你对数据做了什么 - 但是,嘿,你的最后一个问题是正确的方向! 不要猜,基准。

Perl为这类东西提供了Benchmark模块,使用它非常简单。 以下是一些示例代码:

#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);

my $dna;
$dna .= [qw(G A T C)]->[rand 4] for 1 .. 100;

sub frequency_substr {
  my $length = length $dna;
  my %hist;

  for my $pos (0 .. $length) {
    $hist{$pos}{substr $dna, $pos, 1} ++;
  }

  \%hist;
}

sub frequency_split {
  my %hist;
  my $pos = 0;
  for my $char (split //, $dna) {
    $hist{$pos ++}{$char} ++;
  }

  \%hist;
}

sub frequency_regmatch {
  my %hist;

  while ($dna =~ /(.)/g) {
    $hist{pos($dna)}{$1} ++;
  }

  \%hist;
}


cmpthese(-5, # Run each for at least 5 seconds
  { 
    substr => \&frequency_substr,
    split => \&frequency_split,
    regex => \&frequency_regmatch
  }
);

并得到一个结果:

         Rate  regex  split substr
regex  6254/s     --   -26%   -32%
split  8421/s    35%     --    -9%
substr 9240/s    48%    10%     --

原来,substr的速度惊人。 :)

这是我要做的,而不是先尝试在substrsplit之间做出选择:

#!/usr/bin/perl

use strict; use warnings;

my %dist;
while ( my $s = <> ) {
    while ( $s =~ /(.)/g ) {
        ++ $dist{ pos($s) }{ $1 };
    }
}

更新:

我的好奇心得到了我的好处。 这是一个基准:

#!/usr/bin/perl

use strict; use warnings;
use Benchmark qw( cmpthese );

my @chars = qw(A C G T);
my @to_split = my @to_substr = my @to_match = map {
    join '', map $chars[rand @chars], 1 .. 100
} 1 .. 1_000;

cmpthese -1, {
    'split'  => \&bench_split,
    'substr' => \&bench_substr,
    'match'  => \&bench_match,
};

sub bench_split {
    my %dist;
    for my $s ( @to_split ) {
        my @s = split //, $s;
        for my $i ( 0 .. $#s ) {
            ++ $dist{ $i }{ $s[$i] };
        }
    }
}

sub bench_substr {
    my %dist;
    for my $s ( @to_substr ) {
        my $u = length($s) - 1;
        for my $i (0 .. $u) {
            ++ $dist{ $i }{ substr($s, $i, 1) };
        }
    }
}

sub bench_match {
    my %dist;
    for my $s ( @to_match ) {
        while ( $s =~ /(.)/g ) {
            ++ $dist{ pos($s) }{ $1 };
        }
    }
}

输出:

Rate  split  match substr
split  4.93/s     --   -31%   -65%
match  7.11/s    44%     --   -49%
substr 14.0/s   184%    97%     --

我在Mastering Perl中有一个处理这个问题的例子。 你想创建一堆单独的标量,每个标量都带有Perl标量的内存开销,或者将所有内容存储在单个字符串中以减少内存,但可能会做更多的工作。 你说你有很多这些,所以如果你担心记忆,把它们作为单个字符串留下来可能会更好。

掌握Perl还有几章涉及基准测试和分析,如果你对这些很好奇。

以太说要让它先工作,然后再担心其余部分。 部分原因是将操作隐藏在面向任务的界面背后。 一个漂亮的面向对象模块可以为您做到这一点。 如果你不喜欢这种方法,你可以改变它。 但是,更高级别的程序不必更改,因为界面保持不变。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM