Korzystam z następujących oczekujących ciągów znaków o długości 5 znaków:
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";
}
ale zwraca tylko 4 znaki:
anbc
anbd
anbe
anbf
anbg
...
Kiedy jednak zmniejszę liczbę znaków na liście:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
print "$_\n";
}
zwraca poprawnie:
aamid
aamie
aamif
aamig
aamih
...
Czy ktoś może mi powiedzieć, czego tu brakuje, czy istnieje jakiś limit? czy jest na to sposób?
Jeśli robi jakąkolwiek różnicę, zwraca ten sam wynik zarówno w, jak perl 5.26
iperl 5.28
Odpowiedzi:
Wszystko ma pewne ograniczenia.
Oto czysty moduł Perla, który może zrobić to iteracyjnie. Nie generuje całej listy naraz i natychmiast uzyskujesz wyniki:
źródło
NestedLoops
mogą być również użyte:use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } );
(Odpowiedź na wcześniejsze pytanie OP wspomniała, że mogliby tego użyć, gdyby zabrakło pamięci ...)glob
Najpierw tworzy wszystkie możliwe rozszerzenia nazw plików, więc będzie najpierw wygenerować pełną listę z powłoki stylu glob / wzór jest dany. Tylko wtedy będzie iterować, jeśli zostanie użyte w kontekście skalarnym. Dlatego tak trudno (nie?) Uciec z iteratora bez jego wyczerpania; zobacz ten post .W pierwszym przykładzie jest to 26 5 ciągów znaków (
11_881_376
), każdy o długości pięciu znaków. Więc lista ~ 12 milionów łańcuchów, z (naiwnym) sumą przekraczającą 56 Mb ... plus koszty ogólne dla skalara, który moim zdaniem wynosi co najmniej 12 bajtów. Tak więc, co najmniej 100 Mb, przynajmniej na jednej liście. †Nie znam żadnych formalnych ograniczeń długości rzeczy w Perlu (innych niż regex), ale
glob
czy to wszystko wewnętrznie i muszą istnieć nieudokumentowane ograniczenia - być może niektóre bufory są gdzieś przekroczone, wewnętrznie? To trochę przesada.Jeśli chodzi o obejście tego - wygeneruj iteracyjnie tę listę ciągów 5-znakowych, zamiast pozwolić
glob
rzucać swoją magią za kulisy. To absolutnie nie powinno mieć problemu.Jednak uważam, że to wszystko jest nieco duże dla wygody, nawet w tym przypadku. Naprawdę polecam napisać algorytm, który generuje i udostępnia jeden element listy na raz („iterator”), i pracuję z tym.
Istnieją dobre biblioteki, które potrafią to zrobić (i wiele więcej), z których niektóre to Algorytm :: Pętle zalecane w poprzednim poście na ten temat (i w komentarzu), Algorytm :: Kombinatoryka (ten sam komentarz),
Set::CrossProduct
z innej odpowiedzi tutaj ...Zauważ też, że chociaż jest to sprytne zastosowanie
glob
, biblioteka jest przeznaczona do pracy z plikami. Oprócz nadużycia w zasadzie myślę, że sprawdzi każde z (~ 12 milionów) nazw pod kątem prawidłowego wpisu ! (Zobacz tę stronę .) To dużo niepotrzebnej pracy na dysku. (A jeśli użyjesz „globów”, takich jak*
lub?
w niektórych systemach, zwraca listę zawierającą tylko ciągi znaków, które faktycznie mają pliki, więc po cichu uzyskasz inne wyniki.)† Dostaję 56 bajtów dla rozmiaru 5-znakowego skalara. Chociaż dotyczy to deklarowanej zmiennej, która może zająć nieco więcej niż anonimowy skalar, w programie testowym z łańcuchami o długości 4 rzeczywisty całkowity rozmiar jest rzeczywiście o rząd wielkości większy niż naiwnie obliczony. Tak więc rzeczywiste może być rzędu 1 Gb w jednej operacji.
Aktualizacja Prosty program testowy, który generuje tę listę łańcuchów o długości 5 znaków (stosując to samo
glob
podejście), działał przez 15 minut na komputerze klasy serwerowej i zajął 725 Mb pamięci.Na tym serwerze wytworzono odpowiednią liczbę rzeczywistych łańcuchów o długości 5 znaków, pozornie poprawnych.
źródło
glob
. (Będzie to wymagało prostego, innego algorytmu. Być może to, co napisałem w poprzednim pytaniu? To dobre debugowanie - jeśli możesz uzyskać tę listę bez problemów, wiesz, że limity są tutaj przesuwane.) Dodałem szacunkowe rozmiary że dostaję się na pocztę ...time perl -MDevel::Size=total_size -wE'$chs = join ",", "a".."z"; @items = glob "{$chs}"x5; say STDERR "Total memory: ", total_size(\@items)/(1024**2), " Mb"
... i pozwól mi sprawdzić ... teraz uruchomiono go za 30 sekund, co potwierdza, biorąc pod uwagę, jak działa tutaj buforowanie. Sprawdziłem też RSS za pomocą zewnętrznych narzędzi, gdy było w ruchu.26**5
)