Ich führe die folgenden erwarteten Rückgabezeichenfolgen mit 5 Zeichen aus:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'x5) {
print "$_\n";
}
Es werden jedoch nur 4 Zeichen zurückgegeben:
anbc
anbd
anbe
anbf
anbg
...
Wenn ich jedoch die Anzahl der Zeichen in der Liste reduziere:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
print "$_\n";
}
es kehrt korrekt zurück:
aamid
aamie
aamif
aamig
aamih
...
Kann mir bitte jemand sagen, was ich hier vermisse, gibt es eine Grenze? oder gibt es einen weg darum herum?
Wenn es einen Unterschied macht, gibt es in perl 5.26
und das gleiche Ergebnis zurückperl 5.28
Antworten:
Alles hat einige Einschränkungen.
Hier ist ein reines Perl-Modul, das dies iterativ für Sie erledigen kann. Es wird nicht die gesamte Liste auf einmal generiert und Sie erhalten sofort Ergebnisse:
quelle
NestedLoops
könnten auch verwendet werden:use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } );
(Eine Antwort auf eine frühere Frage des OP erwähnte, dass sie dies verwenden könnten, wenn ihnen der SpeicherDer
glob
erste erstellt alle möglichen Dateinamenerweiterungen, sodass zuerst die vollständige Liste aus dem angegebenen Glob / Muster im Shell-Stil generiert wird. Nur dann wird es darüber iterieren, wenn es im skalaren Kontext verwendet wird. Deshalb ist es so schwer (unmöglich?), Dem Iterator zu entkommen, ohne ihn zu erschöpfen. siehe diesen Beitrag .In Ihrem ersten Beispiel sind das 26 5 Zeichenfolgen (
11_881_376
), die jeweils fünf Zeichen lang sind. Also eine Liste von ~ 12 Millionen Zeichenfolgen mit einer (naiven) Summe von mehr als 56 MB ... plus dem Overhead für einen Skalar, der meiner Meinung nach mindestens 12 Bytes oder so beträgt. Also in der Größenordnung von 100 MB, zumindest genau dort in einer Liste. †Ich kenne keine formalen Beschränkungen für die Länge von Dingen in Perl (außer in Regex), aber
glob
macht das alles intern und es muss undokumentierte Beschränkungen geben - vielleicht werden einige Puffer irgendwo intern überlaufen? Es ist ein bisschen übertrieben.Um dies zu umgehen, generieren Sie diese Liste mit 5-Zeichen-Zeichenfolgen iterativ, anstatt
glob
ihre Magie hinter den Kulissen rollen zu lassen . Dann sollte es absolut kein Problem geben.Allerdings finde ich das Ganze auch in diesem Fall ein bisschen groß für Komfort. Ich würde wirklich empfehlen, einen Algorithmus zu schreiben, der jeweils ein Listenelement generiert und bereitstellt (einen "Iterator"), und damit zu arbeiten.
Es gibt gute Bibliotheken, die das können (und vieles mehr), von denen einige Algorithm :: Loops sind , die in einem früheren Beitrag zu diesem Thema (und in einem Kommentar), Algorithm :: Combinatorics (gleicher Kommentar),
Set::CrossProduct
aus einer anderen Antwort empfohlen wurden Hier ...Beachten Sie auch, dass
glob
die Bibliothek , obwohl dies eine clevere Verwendung ist, für die Arbeit mit Dateien gedacht ist. Abgesehen davon, dass es im Prinzip missbraucht wird, denke ich, dass es jeden der (~ 12 Millionen) Namen auf einen gültigen Eintrag überprüft ! (Siehe diese Seite .) Das ist eine Menge nicht benötigter Festplattenarbeit. (Und wenn Sie "Globs" wie*
oder?
auf einigen Systemen verwenden, wird eine Liste mit nur Zeichenfolgen zurückgegeben, die tatsächlich Dateien enthalten, sodass Sie leise unterschiedliche Ergebnisse erhalten.)† Ich erhalte 56 Bytes für eine Größe eines 5-Zeichen-Skalars. Während dies für eine deklarierte Variable gilt, die etwas mehr als einen anonymen Skalar benötigt, ist die tatsächliche Gesamtgröße im Testprogramm mit Zeichenfolgen der Länge 4 tatsächlich um eine gute Größenordnung größer als die naiv berechnete. Die Realität kann also in einem Arbeitsgang in der Größenordnung von 1 GB liegen.
Update Ein einfaches Testprogramm, das diese Liste mit 5 Zeichen langen Zeichenfolgen (nach demselben
glob
Ansatz) generiert, wurde 15 Minuten lang auf einem Computer der Serverklasse ausgeführt und benötigte 725 MB Speicher.Auf diesem Server wurde die richtige Anzahl von 5 Zeichen langen Zeichenfolgen erzeugt, die scheinbar korrekt sind.
quelle
glob
. (Das erfordert einen einfältigen, anderen Algorithmus. Vielleicht das, was ich in Ihrer vorherigen Frage gepostet habe? Das ist gutes Debugging - wenn Sie diese Liste ohne Probleme erhalten können, wissen Sie, dass hier Grenzwerte verschoben werden.) Ich habe einige Größenschätzungen hinzugefügt dass ich zur Posttime perl -MDevel::Size=total_size -wE'$chs = join ",", "a".."z"; @items = glob "{$chs}"x5; say STDERR "Total memory: ", total_size(\@items)/(1024**2), " Mb"
... und lassen Sie mich überprüfen ... jetzt lief es in 30 Sekunden, was es bestätigt, wenn man bedenkt, wie das Cacheing hier funktioniert. Ich habe auch RSS mit externen Tools überprüft, während es lief.26**5
)