Apakah Perl's Glob memiliki batasan?


9

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.26danperl 5.28


Sebelumnya: stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 Gunakan modul yang menyediakan iterator alih-alih menyalahgunakan fungsi glob. p3rl.org/Algorithm::Combinatorics p3rl.org/Algorithm::Loops
daxim

Terima kasih @ Maxim. Masalahnya adalah saya berjuang untuk memuat modul apa pun sekarang, saya punya masalah cpan mengeluh tentang Win32 :: Console, namun ppm tidak tersedia di perl 5.28 juga sehingga saya dapat memuat modul untuk cpan untuk berhenti mengeluh.
Gerry

Terima kasih @zdim menghargai semua waktu dan usaha.
Gerry

Saya baru sadar ... apakah Anda ingin ini dikacak (acak), atau hanya daftar lengkap?
zdim

@zdim hanya daftar lengkap. :)
Gerry

Jawaban:


6

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:

use v5.10;

use Set::CrossProduct;

my $set = Set::CrossProduct->new( [ ([ 'a'..'z' ]) x 5 ] );

while( my $item = $set->get ) {
    say join '', @$item
    }

Kawan, kamu tidak mengerti betapa bahagianya aku sekarang. Terima kasih banyak!!
Gerry

3
Algoritma :: Loops's NestedLoopsjuga 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 ...)
ikegami

8

Yang globpertama 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 globapakah 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 globroll 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::CrossProductdari 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 globpendekatan 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.


@ Jerry Pertama, saya tidak yakin masalahnya ada pada batas; melihat ke dalamnya ... Mungkin menghasilkan daftar terlebih dahulu, iteratif (tidak sekaligus), dan menyimpannya dalam array yang tepat? Itu pasti tidak akan mendekati batas apa pun, "segelintir" string 5-char. (Ini juga diagnostik --- jika itu berhasil maka itu memang beberapa batas internal.)
zdim

@Gerry Tidak perlu modul --- cukup buat daftar (string lima-char) ke dalam array terlebih dahulu, sepotong demi sepotong, alih-alih mengelompokkannya menggunakan 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 ...
zdim

@Gerry 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.
zdim

@Gerry Perilaku yang sama pada v5.29.2 (~ 600Mb sekarang) ... masih menggunakan cache itu di server ini :)))
zdim

@Gerry Hasil dari mesin kelas server lain, dengan v5.16 - 28 menit (diremehkan saat sedang berjalan!) Dan 750Mb. Sekarang ulangi di bawah 5.29.2 dan lagi ~ 600Mb. String yang benar, dan jumlah yang benar (tepatnya 26**5)
zdim
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.