Frage

Ich habe in Perl oft eine Unterroutine, die ein Array mit einigen Informationen füllt.Da ich es auch gewohnt bin, in C++ zu hacken, mache ich es in Perl oft so und verwende dabei Referenzen:

my @array;
getInfo(\@array);

sub getInfo {
   my ($arrayRef) = @_;
   push @$arrayRef, "obama";
   # ...
}

statt der einfacheren Version:

my @array = getInfo();

sub getInfo {
   my @array;
   push @array, "obama";
   # ...
   return @array;
}

Der Grund liegt natürlich darin, dass ich nicht möchte, dass das Array lokal in der Unterroutine erstellt und dann bei der Rückkehr kopiert wird.

Ist das richtig?Oder optimiert Perl das trotzdem weg?

War es hilfreich?

Lösung

Was ist eine Array-Referenz an erster Stelle zurückkehrt?

sub getInfo {
  my $array_ref = [];
  push @$array_ref, 'foo';
  # ...
  return $array_ref;
}

my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};

Bearbeiten nach Dehmann Kommentar:

Es ist auch möglich, ein normales Array in der Funktion zu verwenden, und einen Verweis darauf zurück.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return \@array;
}      

Andere Tipps

Passing Referenzen sind effizienter, aber der Unterschied ist nicht so groß wie in C ++. Das Argument Wert selbst (das heißt: die Werte im Array) werden immer als Referenz übergibt sowieso (zurückgegebenen Werte werden jedoch kopiert)

.

Die Frage ist: ist es wichtig? Die meiste Zeit, ist es nicht. Wenn Sie 5 Elemente sind wiederkehrende, nicht die Mühe, darüber. Wenn Sie Rückkehr / vorbei 100'000 Elemente, Verwendung Referenzen. Nur es optimiert, wenn es zu einem Engpass ist.

Wenn ich an Ihrem Beispiel schauen und darüber nachdenken, was Sie tun mögen, ich bin es gewohnt, es auf diese Weise zu schreiben:

sub getInfo {
  my @array;
  push @array, 'obama';
  # ...
  return \@array;
}

Es scheint mir, als einfache Version , wenn ich zurückkommen müssen große Datenmenge. Es ist nicht nötig zuweisen Array außerhalb sub, wie Sie in Ihrem ersten Code-Schnipsel geschrieben, weil my es für Sie tun. Auf jeden Fall sollten Sie vorzeitige Optimierung als Leon Timmermans nicht vorschlagen .

das letzte Wiederkäuen zu beantworten, nein, nicht Perl nicht optimieren entfernt. Es kann nicht wirklich, weil ein Feld zurückgibt und eine skalare Rückkehr sind grundverschieden.

Wenn Sie mit großen Datenmengen zu tun haben oder wenn die Leistung ein wichtiges Anliegen ist, dann C Gewohnheiten werden Sie gut - Pass und Rückverweise auf Datenstrukturen, anstatt die Strukturen selbst, so dass sie nicht brauchen kopiert. Aber, wie Leon Timmermans wies darauf hin, die überwiegende Mehrheit der Zeit, sind Sie mit kleineren Datenmengen zu tun und die Leistung ist nicht so große Sache, tun Sie es so in welcher Weise auch immer scheint die meisten lesbar.

Das ist die Art, wie ich normalerweise ein Array zurück.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return @array if wantarray;
  return \@array;
}

Auf diese Weise wird es funktionieren, wie Sie wollen, in Skalar oder eine Liste Kontexten.

my $array = getInfo;
my @array = getInfo;

$array->[0] == $array[0];

# same length
@$array == @array;

würde ich nicht versuchen, es zu optimieren, wenn Sie wissen, dass es ein langsamer Teil des Codes ist. Selbst dann würde ich Benchmarks verwenden, um festzustellen, welches Unterprogramm tatsächlich schneller ist.

Es gibt zwei Überlegungen.Die offensichtliche Frage ist: Wie groß wird Ihr Array werden?Wenn es sich um weniger als ein paar Dutzend Elemente handelt, spielt die Größe keine Rolle (es sei denn, Sie führen eine Mikrooptimierung für eine schnell aufgerufene Funktion durch, aber Sie müssten zunächst ein Speicherprofil erstellen, um dies zu beweisen).

Das ist der einfache Teil.Der oft übersehene zweite Aspekt ist die Schnittstelle.Wie wird das zurückgegebene Array verwendet?Dies ist wichtig, da die Dereferenzierung ganzer Arrays in Perl ziemlich schrecklich ist.Zum Beispiel:

for my $info (@{ getInfo($some, $args) }) {
    ...
}

Das ist hässlich.Das ist viel besser.

for my $info ( getInfo($some, $args) ) {
    ...
}

Es eignet sich auch für Mapping und Grepping.

my @info = grep { ... } getInfo($some, $args);

Die Rückgabe einer Array-Referenz kann jedoch praktisch sein, wenn Sie einzelne Elemente auswählen möchten:

my $address = getInfo($some, $args)->[2];

Das ist einfacher als:

my $address = (getInfo($some, $args))[2];

Oder:

my @info = getInfo($some, $args);
my $address = $info[2];

Aber an diesem Punkt sollten Sie sich fragen, ob @info wirklich eine Liste oder ein Hash ist.

my $address = getInfo($some, $args)->{address};

Was Sie nicht tun sollten, ist zu haben getInfo() Gibt eine Array-Referenz im Skalarkontext und ein Array im Listenkontext zurück.Dadurch wird die traditionelle Verwendung des skalaren Kontexts als Array-Länge durcheinander gebracht, was den Benutzer überraschen wird.

Zum Schluss werde ich mein eigenes Modul anschließen, Methode::Signaturen, da es einen Kompromiss für die Übergabe von Array-Referenzen darstellt, ohne dass die Array-Ref-Syntax verwendet werden muss.

use Method::Signatures;

method foo(\@args) {
    print "@args";      # @args is not a copy
    push @args, 42;   # this alters the caller array
}

my @nums = (1,2,3);
Class->foo(\@nums);   # prints 1 2 3
print "@nums";        # prints 1 2 3 42

Dies geschieht durch die Magie von Daten::Alias.

3 andere potenziell große Leistungsverbesserungen, wenn Sie eine ganze, ziemlich große Datei lesen und es in ein Array Slicing:

  1. Schalten Sie BUFFERING mit sysread () anstelle von read () (Handbuch warnt etwa Mischen)
  2. Pre-verlängert das Array durch das letzte Element der Bewertung -     spart Speicherzuordnungen
  3. Verwenden Sie auspacken (), um schnell aufspalten Daten wie uint16_t Grafiken Kanaldaten

Vorbei an die Funktion ein Array ref ermöglicht das Hauptprogramm mit einer einfachen Anordnung zu beschäftigen, während die Write-Once-and-Forget-Arbeiter Funktion der komplizierteren „$ @“ Pfeil und verwendet -> [$ II] Zugangsformen. Als ganz C'ish, ist es wahrscheinlich schnell sein!

Ich weiß nichts über Perl so ist dies eine sprachneutrale Antwort.

Es ist in einem gewissen Sinne, ineffizient ein Array aus einem Unterprogramm in das rufende Programm zu kopieren. Die Ineffizienz entsteht in dem zusätzlichen Speicher verwendet und die Zeit genommen, um die Daten von einem Ort zum anderen kopieren. Auf der anderen Seite, für alle, aber die größte Arrays, können Sie nicht eine verdammt, und vielleicht Arrays bevorzugen für Eleganz abzuschreiben, cussedness oder irgendeinen anderen Grund.

Die effiziente Lösung für das Unterprogramm des aufrufende Programm der Adresse des Arrays zu übergeben. Wie gesagt, ich habe keine Ahnung von Perl Standardverhalten in dieser Hinsicht. Aber einige Sprachen bieten dem Programmierer die Möglichkeit, welcher Ansatz zu wählen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top