7 Stimmen

Wenn Sie auf einzelne Zeichen in einer Zeichenkette in Perl zugreifen, ist substr oder Splitting in ein Array schneller?

Ich schreibe ein Perl-Skript, in dem ich eine Schleife über jedes Zeichen einer Zeichenkette ausführen muss. Es gibt eine Menge Strings, und jeder ist 100 Zeichen lang (es sind kurze DNA-Sequenzen, falls Sie sich wundern).

Ist es also schneller, die substr jedes Zeichen einzeln zu extrahieren, oder ist es schneller, wenn split die Zeichenkette in ein Array umwandeln und dann über dieses Array iterieren?

Während ich auf eine Antwort warte, werde ich wohl mal nachlesen, wie man in Perl Benchmarks erstellt.

9voto

hobbs Punkte 204816

Es hängt wirklich davon ab, was genau Sie mit Ihren Daten machen - aber hey, mit Ihrer letzten Frage sind Sie auf dem richtigen Weg! Raten Sie nicht, sondern messen Sie.

Perl bietet die Benchmark Modul für genau diese Art von Dingen, und die Verwendung ist wirklich ziemlich einfach. Hier ist ein kleines Codebeispiel für den Anfang:

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

Und ein Beispielergebnis:

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

Es stellt sich heraus, dass substr überraschend schnell ist :)

4voto

Sinan Ünür Punkte 114993

Ich würde Folgendes tun, anstatt zuerst zu versuchen, zwischen folgenden Optionen zu wählen substr y split :

#!/usr/bin/perl

use strict; use warnings;

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

Aktualisierung:

Meine Neugierde hat mich übermannt. Hier ist ein Benchmark:

#!/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%     --

3voto

brian d foy Punkte 124323

Ich habe ein Beispiel in Perl beherrschen Umgang mit diesem Problem. Wollen Sie einen Haufen einzelner Skalare erstellen, von denen jeder den Speicher-Overhead eines Perl-Skalars mit sich bringt, oder alles in einem einzigen String speichern, um Speicher zu sparen, aber vielleicht mehr Arbeit zu machen. Sie sagen, dass Sie eine Menge davon haben, so dass sie als einzelne Strings könnte viel besser für Sie arbeiten, wenn Sie über Speicher besorgt sind.

Perl beherrschen hat auch einige Kapitel, die sich mit Benchmarking und Profilerstellung befassen, falls Sie daran interessiert sind.

Ether sagt, man solle es zuerst zum Laufen bringen und sich später um den Rest kümmern. Ein Teil davon ist, die Operationen hinter einer aufgabenorientierten Schnittstelle zu verstecken. Ein schönes objektorientiertes Modul kann das für Sie tun. Wenn Ihnen die Implmentierung nicht gefällt, ändern Sie sie. Die Programme auf der höheren Ebene müssen sich jedoch nicht ändern, da die Schnittstelle die gleiche bleibt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X