Saya menjalankan string pengembalian 5 karakter berikut yang diharapkan:
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";
}
tetapi hanya mengembalikan 4 karakter:
anbc
anbd
anbe
anbf
anbg
...
Namun, ketika saya mengurangi jumlah karakter dalam daftar:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
print "$_\n";
}
kembali dengan benar:
aamid
aamie
aamif
aamig
aamih
...
Bisakah seseorang tolong beri tahu saya apa yang saya lewatkan di sini, apakah ada semacam batasan? atau adakah cara untuk mengatasi ini?
Jika ada bedanya, ia mengembalikan hasil yang sama di keduanya perl 5.26
danperl 5.28
Jawaban:
Semuanya memiliki beberapa batasan.
Berikut adalah modul Perl murni yang dapat melakukannya untuk Anda secara iteratif. Itu tidak menghasilkan seluruh daftar sekaligus dan Anda mulai mendapatkan hasil dengan segera:
sumber
NestedLoops
juga dapat digunakan:use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } );
(Jawaban untuk pertanyaan sebelumnya oleh OP menyebutkan bahwa mereka dapat menggunakan ini jika mereka kehabisan memori ...)Yang
glob
pertama menciptakan semua kemungkinan ekspansi nama file, jadi itu akan menghasilkan daftar lengkap dari glob-style shell-pola yang diberikan. Hanya kemudian akan beralih di atasnya, jika digunakan dalam konteks skalar. Itu sebabnya sangat sulit (mustahil?) Untuk melarikan diri dari iterator tanpa melelahkannya; lihat posting ini .Dalam contoh pertama Anda yaitu 26 5 string (
11_881_376
), masing-masing panjang lima karakter. Jadi daftar ~ 12 juta string, dengan (naif) total lebih dari 56Mb ... ditambah overhead untuk skalar, yang saya pikir minimal 12 byte atau lebih. Jadi pada urutan 100MB, paling tidak, di sana dalam satu daftar. †Saya tidak mengetahui adanya batasan formal pada panjang hal di Perl (selain di regex) tetapi
glob
apakah semua itu secara internal dan harus ada batas tidak berdokumen - mungkin beberapa buffer dikuasai di suatu tempat, secara internal? Itu agak berlebihan.Adapun cara untuk mengatasi ini - buat daftar string 5-char iteratif, daripada membiarkan
glob
roll sihirnya di belakang layar. Maka itu sama sekali tidak seharusnya memiliki masalah.Namun, saya menemukan semuanya agak besar untuk kenyamanan, bahkan dalam kasus itu. Saya benar-benar merekomendasikan untuk menulis algoritma yang menghasilkan dan menyediakan elemen daftar satu per satu ("iterator"), dan bekerja dengannya.
Ada perpustakaan yang baik yang dapat melakukan itu (dan banyak lagi), beberapa di antaranya adalah Algoritma :: Loop direkomendasikan dalam posting sebelumnya tentang masalah ini (dan dalam komentar), Algoritma :: Combinatorics (komentar yang sama),
Set::CrossProduct
dari jawaban lain disini ...Juga perhatikan bahwa, meskipun ini adalah penggunaan yang cerdas
glob
, perpustakaan dimaksudkan untuk bekerja dengan file. Terlepas dari menyalahgunakannya secara prinsip, saya pikir itu akan memeriksa setiap (12 juta) nama untuk entri yang benar ! (Lihat halaman ini .) Itu banyak pekerjaan disk yang tidak dibutuhkan. (Dan jika Anda menggunakan "gumpalan" seperti*
atau?
pada beberapa sistem, ia mengembalikan daftar dengan hanya string yang benar-benar memiliki file, sehingga Anda akan diam-diam mendapatkan hasil yang berbeda.)† Saya mendapatkan 56 byte untuk ukuran skalar 5-char. Sementara itu untuk variabel yang dideklarasikan, yang mungkin memerlukan sedikit lebih banyak daripada skalar anonim, dalam program uji dengan panjang-4 string ukuran total sebenarnya memang urutan besarnya lebih besar daripada yang dihitung secara naif. Jadi yang asli mungkin berada di urutan 1Gb, dalam satu operasi.
Pembaruan Sebuah program uji sederhana yang menghasilkan daftar string 5-char panjang (menggunakan
glob
pendekatan yang sama ) berjalan selama 15-ish menit pada mesin kelas server dan mengambil memori 725 Mb.Itu memang menghasilkan jumlah yang tepat dari string panjang 5-char yang sebenarnya, tampaknya benar, di server ini.
sumber
glob
. (Itu akan membutuhkan beberapa algoritma sederhana yang berpikiran lain. Mungkin yang saya posting di pertanyaan Anda sebelumnya? Itu debugging yang bagus - jika Anda bisa mendapatkan daftar itu tanpa masalah maka Anda tahu bahwa batasan sedang ditekan di sini.) Saya menambahkan beberapa perkiraan ukuran bahwa saya akan sampai ke pos ...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"
... dan biarkan saya memeriksa ... sekarang itu berjalan dalam 30 detik, apa yang mengonfirmasi itu mengingat cara kerja cache di sini. Saya juga memeriksa RSS dengan alat eksternal ketika sedang berjalan.26**5
)