C-artige Arrays in Perl

8

Ich möchte große Arrays von (4 Byte) Ganzzahlen im Speicher erstellen und bearbeiten. Im Großen und Ganzen meine ich in der Größenordnung von Hunderten von Millionen. Jede Zelle im Array wird als Zähler für eine Position auf einem Chromosom fungieren. Alles, was ich brauche, ist, dass es in den Speicher passt und schnellen (O (1)) Zugriff auf Elemente hat. Die Sache, die ich zähle, ist keine spärliche Eigenschaft, also kann ich kein Sparse-Array verwenden.

Ich kann das nicht mit einer normalen Perl-Liste machen, weil Perl (zumindest auf meiner Maschine) 64 Bytes pro Element verwendet, also sind die Genome der meisten Organismen, mit denen ich arbeite, einfach zu groß. Ich habe versucht, die Daten auf der Festplatte über SQLite und Hash-Verknüpfung zu speichern, und obwohl sie funktionieren, sind sie sehr langsam, besonders auf normalen Laufwerken. (Es funktioniert einigermaßen in Ordnung, wenn ich auf 4-Laufwerk raid 0 laufen).

Ich dachte, ich könnte PDL-Arrays verwenden, b / c PDL speichert seine Arrays genauso wie C und verwendet nur 4 Bytes pro Element. Ich fand jedoch, dass die Update-Geschwindigkeit im Vergleich zu Perl-Listen unerträglich langsam ist:

%Vor%

Rückkehr:

%Vor%

Weiß jemand, wie man die Leistung von pdl set () erhöht oder von einem anderen Modul weiß, dass dies möglich ist?

    
user1481 16.03.2012, 01:35
quelle

7 Antworten

8

Ich kann nicht sagen, welche Art von Leistung Sie erhalten werden, aber ich empfehle, die vec -Funktion zu verwenden, dokumentiert hier , um einen String in Bitfelder aufzuteilen. Ich habe experimentiert und festgestellt, dass mein Perl eine Zeichenfolge bis zu 500_000_000 Zeichen lang toleriert. Das entspricht 125.000.000 32-Bit-Werten.

%Vor%

Wenn das nicht genug ist, kann es im Build von Perl etwas geben, das das Limit steuert. Alternativ, wenn Sie denken, dass Sie kleinere Felder erhalten können - sagen wir 16-Bit-Zählungen - akzeptiert vec Feldbreiten jeder Potenz von 2 bis 32.

Edit: Ich glaube, dass die String-Größenbeschränkung mit der maximalen privaten Größe von 2 GB bei 32-Bit-Windows-Prozessen zusammenhängt. Wenn Sie mit Linux arbeiten oder eine 64-Bit-Perl haben, können Sie glücklicher sein als ich.

Ich habe Ihr Benchmark-Programm wie folgt hinzugefügt

%Vor%

geben diese Ergebnisse

%Vor%

% vec ist also zwei Drittel der Geschwindigkeit eines nativen Arrays. Vermutlich ist das akzeptabel.

    
Borodin 16.03.2012, 02:05
quelle
7

Der gewünschte PDL-Befehl lautet indadd . (Danke an Chris Marshall, PDL Pumpking, dafür, dass er mir das anderswo gezeigt hat .)

PDL ist für das konzipiert, was ich "vektorisierte" Operationen nenne. Im Vergleich zu C-Operationen sind Perl-Operationen ziemlich langsam. Daher sollten Sie die Anzahl der Aufrufe der PDL-Methode auf ein Minimum beschränken und jeden Aufruf viel Arbeit verrichten lassen. Mit diesem Benchmark können Sie beispielsweise die Anzahl der Aktualisierungen festlegen, die in einem einzelnen Vorgang ausgeführt werden (als Befehlszeilenparameter). Die Perl-Seite muss eine Schleife bilden, aber die PDL-Seite führt nur fünf Funktionsaufrufe aus:

%Vor%

Wenn ich das mit einem Argument von 1 führe, bekomme ich eine noch schlechtere Leistung als bei der Verwendung von set , was ich erwartet habe:

%Vor%

Das ist eine Menge Grund zum Nachmachen! Aber halt da drinnen. Wenn wir 100 Iterationen pro Runde machen, erhalten wir eine Verbesserung:

%Vor%

Und mit 10.000 Updates pro Runde übertrifft PDL Perl um den Faktor vier:

%Vor%

PDL arbeitet bei noch größeren Werten weiterhin etwa 4x schneller als normale Perl.

Beachten Sie, dass die Leistung von PDL bei komplexeren Vorgängen beeinträchtigt werden kann. Dies liegt daran, dass PDL große, aber temporäre Arbeitsbereiche für Zwischenoperationen zuweist und abbaut. In diesem Fall sollten Sie in Betracht ziehen, Inline::Pdlpp zu verwenden. Allerdings ist das kein Anfängerwerkzeug, also springen Sie nicht dorthin, bis Sie bestimmt haben, dass es wirklich das Beste für Sie ist.

Eine weitere Alternative zu all dem ist Inline::C like so:

zu verwenden %Vor%

Bei mir schlägt die Inline-Funktion sowohl Perl als auch PDL durchgängig. Für größere Werte von $updates_per_round , sagen wir 1.000, bekomme ich Inline::C 's Version ungefähr 5x schneller als reines Perl und zwischen 1.2x und 2x schneller als PDL. Selbst wenn $updates_per_round nur 1 ist, wobei Perl PDL leicht schlägt, ist der Inline-Code 2,5x schneller als der Perl-Code.

Wenn dies alle ist, die Sie ausführen müssen, empfehle ich Inline::C .

Wenn Sie jedoch viele Manipulationen an Ihren Daten vornehmen müssen, halten Sie sich am besten an PDL für seine Leistung, Flexibilität und Leistung. Im Folgenden erfahren Sie, wie Sie vec() mit PDL-Daten verwenden können.

    
David Mertens 22.03.2012 17:02
quelle
4
___ antwort10211361 ___

PDL::set() und PDL::get() sind eher als Lernhilfe gedacht als alles andere. Sie stellen den pessimalen Weg dar, auf PDL-Variablen zuzugreifen. Sie wären viel besser dran mit einigen der integrierten Massenzugriffsroutinen. Der PDL-Konstruktor selbst akzeptiert Perl-Listen:

%Vor%

und ist ziemlich schnell. Sie können Ihre Daten auch direkt aus einer ASCII-Datei mit PDL::rcols oder aus einer Binärdatei mit einer von vielen IO-Routinen laden. Wenn Sie die Daten als gepackten String in der Maschinenreihenfolge haben, können Sie sogar direkt auf den PDL-Speicher zugreifen:

%Vor%

Beachten Sie auch, dass Sie "Ihren Kuchen haben und es auch essen" können, indem Sie PDL-Objekte verwenden, um Ihre Arrays von Ganzzahlen, PDL-Berechnungen (wie indadd ) für die Manipulation der Daten im großen Maßstab zu halten. co_de% direkt auf den PDL-Daten als String, den Sie über die Methode vec() erhalten:

%Vor%

Sie müssen get_dataref der Daten eingeben, wenn Sie sich auf einem Little-Endian-System befinden:

%Vor%

Et, voila!

    
___ answer9730716 ___

PDL gewinnt, wenn die Operationen eingefädelt werden können, anscheinend ist es nicht für wahlfreien Zugriff und Zuweisung optimiert. Vielleicht könnte jemand mit mehr PDL-Wissen helfen.

    
___ answer9730875 ___

Ich kann nicht sagen, welche Art von Leistung Sie erhalten werden, aber ich empfehle, die bswap4 -Funktion zu verwenden, dokumentiert hier , um einen String in Bitfelder aufzuteilen. Ich habe experimentiert und festgestellt, dass mein Perl eine Zeichenfolge bis zu %code% Zeichen lang toleriert. Das entspricht 125.000.000 32-Bit-Werten.

%Vor%

Wenn das nicht genug ist, kann es im Build von Perl etwas geben, das das Limit steuert. Alternativ, wenn Sie denken, dass Sie kleinere Felder erhalten können - sagen wir 16-Bit-Zählungen - akzeptiert %code% Feldbreiten jeder Potenz von 2 bis 32.

Edit: Ich glaube, dass die String-Größenbeschränkung mit der maximalen privaten Größe von 2 GB bei 32-Bit-Windows-Prozessen zusammenhängt. Wenn Sie mit Linux arbeiten oder eine 64-Bit-Perl haben, können Sie glücklicher sein als ich.

Ich habe Ihr Benchmark-Programm wie folgt hinzugefügt

%Vor%

geben diese Ergebnisse

%Vor%

% %code% ist also zwei Drittel der Geschwindigkeit eines nativen Arrays. Vermutlich ist das akzeptabel.

    
___ qstntxt ___

Ich möchte große Arrays von (4 Byte) Ganzzahlen im Speicher erstellen und bearbeiten. Im Großen und Ganzen meine ich in der Größenordnung von Hunderten von Millionen. Jede Zelle im Array wird als Zähler für eine Position auf einem Chromosom fungieren. Alles, was ich brauche, ist, dass es in den Speicher passt und schnellen (O (1)) Zugriff auf Elemente hat. Die Sache, die ich zähle, ist keine spärliche Eigenschaft, also kann ich kein Sparse-Array verwenden.

Ich kann das nicht mit einer normalen Perl-Liste machen, weil Perl (zumindest auf meiner Maschine) 64 Bytes pro Element verwendet, also sind die Genome der meisten Organismen, mit denen ich arbeite, einfach zu groß. Ich habe versucht, die Daten auf der Festplatte über SQLite und Hash-Verknüpfung zu speichern, und obwohl sie funktionieren, sind sie sehr langsam, besonders auf normalen Laufwerken. (Es funktioniert einigermaßen in Ordnung, wenn ich auf 4-Laufwerk raid 0 laufen).

Ich dachte, ich könnte PDL-Arrays verwenden, b / c PDL speichert seine Arrays genauso wie C und verwendet nur 4 Bytes pro Element. Ich fand jedoch, dass die Update-Geschwindigkeit im Vergleich zu Perl-Listen unerträglich langsam ist:

%Vor%

Rückkehr:

%Vor%

Weiß jemand, wie man die Leistung von pdl set () erhöht oder von einem anderen Modul weiß, dass dies möglich ist?

    
___ answer9732079 ___

Packed :: Array auf CPAN könnte helfen.

  

Packed :: Array stellt eine gepackte vorzeichenbehaftete Integer-Array-Klasse zur Verfügung. Arrays, die mit Packed :: Array erstellt wurden, können nur vorzeichenbehaftete Ganzzahlen enthalten, die mit Ihren plattformeigenen Ganzzahlen übereinstimmen, aber nur so viel Speicher belegen, wie tatsächlich benötigt wird, um diese Ganzzahlen zu speichern. Für 32-Bit-Systeme benötigen sie also nicht etwa 20 Byte pro Array-Eintrag, sondern nur 4.

    
___ tag123arrays ___ Ein Array ist eine geordnete Datenstruktur, die aus einer Sammlung von Elementen (Werten oder Variablen) besteht, die jeweils durch einen oder mehrere Indizes identifiziert werden. Wenn Sie nach bestimmten Varianten von Arrays fragen, verwenden Sie stattdessen diese verwandten Tags: [Vektor], [Arraylist], [Matrix]. Wenn Sie dieses Tag verwenden, markieren Sie die Frage auch mit der verwendeten Programmiersprache, es sei denn, Ihre Frage bezieht sich nicht auf eine bestimmte Programmiersprache. ___ tag123perl ___ Perl ist eine prozedurale, allgemeine Programmiersprache für allgemeine Zwecke, die für ihre native Unterstützung von regulären Ausdrücken und String-Parsing-Funktionen bekannt ist. Bitte verwenden Sie diesen Tag für Fragen zu Perl im Allgemeinen. Für Dinge, die mit der neuen (aber verwandten) Sprache "Perl 6" zu tun haben, verwenden Sie bitte das perl6-Tag. Verwenden Sie für reguläre Ausdrücke nach Perl-Art in anderen Sprachen das Regex-Tag oder, falls sie auf der PCRE-Bibliothek basieren, das PCRE-Tag. ___ tag123pdl ___ PDL ("Perl Data Language") gibt Standard-Perl die Möglichkeit, die großen N-dimensionalen Datenfelder, die die Grundlage wissenschaftlichen Rechnens bilden, kompakt zu speichern und schnell zu bearbeiten. ___ answer9827008 ___

Der gewünschte PDL-Befehl lautet %code% . (Danke an Chris Marshall, PDL Pumpking, dafür, dass er mir das anderswo gezeigt hat .)

PDL ist für das konzipiert, was ich "vektorisierte" Operationen nenne. Im Vergleich zu C-Operationen sind Perl-Operationen ziemlich langsam. Daher sollten Sie die Anzahl der Aufrufe der PDL-Methode auf ein Minimum beschränken und jeden Aufruf viel Arbeit verrichten lassen. Mit diesem Benchmark können Sie beispielsweise die Anzahl der Aktualisierungen festlegen, die in einem einzelnen Vorgang ausgeführt werden (als Befehlszeilenparameter). Die Perl-Seite muss eine Schleife bilden, aber die PDL-Seite führt nur fünf Funktionsaufrufe aus:

%Vor%

Wenn ich das mit einem Argument von 1 führe, bekomme ich eine noch schlechtere Leistung als bei der Verwendung von %code% , was ich erwartet habe:

%Vor%

Das ist eine Menge Grund zum Nachmachen! Aber halt da drinnen. Wenn wir 100 Iterationen pro Runde machen, erhalten wir eine Verbesserung:

%Vor%

Und mit 10.000 Updates pro Runde übertrifft PDL Perl um den Faktor vier:

%Vor%

PDL arbeitet bei noch größeren Werten weiterhin etwa 4x schneller als normale Perl.

Beachten Sie, dass die Leistung von PDL bei komplexeren Vorgängen beeinträchtigt werden kann. Dies liegt daran, dass PDL große, aber temporäre Arbeitsbereiche für Zwischenoperationen zuweist und abbaut. In diesem Fall sollten Sie in Betracht ziehen, %code% zu verwenden. Allerdings ist das kein Anfängerwerkzeug, also springen Sie nicht dorthin, bis Sie bestimmt haben, dass es wirklich das Beste für Sie ist.

Eine weitere Alternative zu all dem ist %code% like so:

zu verwenden %Vor%

Bei mir schlägt die Inline-Funktion sowohl Perl als auch PDL durchgängig. Für größere Werte von %code% , sagen wir 1.000, bekomme ich %code% 's Version ungefähr 5x schneller als reines Perl und zwischen 1.2x und 2x schneller als PDL. Selbst wenn %code% nur 1 ist, wobei Perl PDL leicht schlägt, ist der Inline-Code 2,5x schneller als der Perl-Code.

Wenn dies alle ist, die Sie ausführen müssen, empfehle ich %code% .

Wenn Sie jedoch viele Manipulationen an Ihren Daten vornehmen müssen, halten Sie sich am besten an PDL für seine Leistung, Flexibilität und Leistung. Im Folgenden erfahren Sie, wie Sie %code% mit PDL-Daten verwenden können.

    
___ answer16504487 ___

Meine obige Antwort ist vielleicht wertlos ... das könnte helfen, .. ..

%Vor%

jetzt, das wird nicht funktionieren, wenn Sie 16 GB RAM haben und

verwenden %Vor%     
___ answer10214702 ___

seit der Verwendung von Ganzzahlen, die für die Verwendung in Ordnung sein sollten mit Chromosomen versuchen Sie dies

%Vor%

und der Ausgang, den ich daraus habe, war ...

%Vor%

zeigt einen großen Leistungsunterschied von Anfang an, als ich diesen Code zum ersten Mal ausprobiert habe Hinzufügen in meine 2 Cent habe ich

%Vor%     
___ qstnhdr ___ C-artige Arrays in Perl ___
Craig DeForest 18.04.2012 14:19
quelle
2

Packed :: Array auf CPAN könnte helfen.

  

Packed :: Array stellt eine gepackte vorzeichenbehaftete Integer-Array-Klasse zur Verfügung. Arrays, die mit Packed :: Array erstellt wurden, können nur vorzeichenbehaftete Ganzzahlen enthalten, die mit Ihren plattformeigenen Ganzzahlen übereinstimmen, aber nur so viel Speicher belegen, wie tatsächlich benötigt wird, um diese Ganzzahlen zu speichern. Für 32-Bit-Systeme benötigen sie also nicht etwa 20 Byte pro Array-Eintrag, sondern nur 4.

    
Ilion 16.03.2012 04:52
quelle
2

seit der Verwendung von Ganzzahlen, die für die Verwendung in Ordnung sein sollten mit Chromosomen versuchen Sie dies

%Vor%

und der Ausgang, den ich daraus habe, war ...

%Vor%

zeigt einen großen Leistungsunterschied von Anfang an, als ich diesen Code zum ersten Mal ausprobiert habe Hinzufügen in meine 2 Cent habe ich

%Vor%     
Mark R Baker 18.04.2012 17:29
quelle
2

PDL gewinnt, wenn die Operationen eingefädelt werden können, anscheinend ist es nicht für wahlfreien Zugriff und Zuweisung optimiert. Vielleicht könnte jemand mit mehr PDL-Wissen helfen.

    
Joel Berger 16.03.2012 01:40
quelle
0

Meine obige Antwort ist vielleicht wertlos ... das könnte helfen, .. ..

%Vor%

jetzt, das wird nicht funktionieren, wenn Sie 16 GB RAM haben und

verwenden %Vor%     
Mark Baker 12.05.2013 05:28
quelle

Tags und Links