Glob của Perl có giới hạn không?


9

Tôi đang chạy chuỗi trả về mong đợi sau đây gồm 5 ký tự:

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";
}

nhưng nó chỉ trả về 4 ký tự:

anbc
anbd
anbe
anbf
anbg
...

Tuy nhiên, khi tôi giảm số lượng ký tự trong danh sách:

while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
  print "$_\n";
}

nó trả về chính xác:

aamid
aamie
aamif
aamig
aamih
...

Ai đó có thể vui lòng cho tôi biết những gì tôi đang thiếu ở đây, có giới hạn nào không? hoặc có một cách xung quanh này?

Nếu nó làm cho bất kỳ sự khác biệt, nó trả về cùng một kết quả trong cả hai perl 5.26perl 5.28


Trước đây: stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 Sử dụng một mô-đun cung cấp một trình vòng lặp thay vì lạm dụng chức năng toàn cầu. p3rl.org/Alacticm::Combinatorics p3rl.org/Alacticm::Loops
daxim 16/11/19

Cảm ơn @daxim. Vấn đề là hiện tại tôi đang phải vật lộn để tải các mô-đun, tôi có một vấn đề về cpan phàn nàn về Win32 :: Console, nhưng ppm cũng không có sẵn trong perl 5.28 vì vậy tôi có thể tải mô-đun cho cpan để ngừng phàn nàn.
Gerry

Cảm ơn @zdim đánh giá cao tất cả thời gian và nỗ lực.
Gerry

Tôi mới nhận ra ... bạn có muốn xáo trộn (ngẫu nhiên) này không, hay chỉ là danh sách đầy đủ?
zdim

@zdim chỉ là một danh sách đầy đủ. :)
Gerry

Câu trả lời:


6

Mọi thứ đều có một số hạn chế.

Đây là một mô-đun Perl thuần túy có thể làm điều đó cho bạn lặp đi lặp lại. Nó không tạo ra toàn bộ danh sách cùng một lúc và bạn bắt đầu nhận được kết quả ngay lập tức:

use v5.10;

use Set::CrossProduct;

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

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

Man, bạn không hiểu làm thế nào tôi hạnh phúc ngay bây giờ. Cảm ơn rât nhiều!!
Gerry

3
Thuật toán :: Loops NestedLoopscũng có thể được sử dụng: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (Câu trả lời cho câu hỏi trước đó của OP đã đề cập rằng họ có thể sử dụng điều này nếu hết bộ nhớ ...)
ikegami

8

Cái globđầu tiên tạo ra tất cả các mở rộng tên tệp có thể, vì vậy trước tiên nó sẽ tạo danh sách đầy đủ từ kiểu toàn cầu / kiểu vỏ mà nó được đưa ra. Chỉ sau đó nó sẽ lặp đi lặp lại trên nó, nếu được sử dụng trong bối cảnh vô hướng. Đó là lý do tại sao rất khó (không thể?) Để thoát khỏi trình vòng lặp mà không làm cạn kiệt nó; thấy bài này .

Trong ví dụ đầu tiên của bạn đó là 26 5 chuỗi ( 11_881_376), mỗi chuỗi dài 5 ký tự. Vì vậy, một danh sách ~ 12 triệu chuỗi, với tổng số (ngây thơ) vượt quá 56Mb ... cộng với chi phí cho một vô hướng, mà tôi nghĩ tối thiểu là 12 byte hoặc hơn thế. Vì vậy, theo thứ tự của 100Mb, ít nhất, ngay trong một danh sách.

Tôi không nhận thức được bất kỳ giới hạn chính thức nào về độ dài của mọi thứ trong Perl (ngoài regex) nhưng globliệu tất cả những gì bên trong và phải có giới hạn không có giấy tờ - có lẽ một số bộ đệm bị tràn ngập ở đâu đó, trong nội bộ? Nó là một chút quá mức.

Đối với cách này - tạo ra danh sách các chuỗi 5 ký tự lặp đi lặp lại, thay vì để phép globthuật của nó đằng sau hậu trường. Sau đó, nó hoàn toàn không có vấn đề.

Tuy nhiên, tôi thấy toàn bộ điều này hơi lớn cho sự thoải mái, ngay cả trong trường hợp đó. Tôi thực sự khuyên bạn nên viết một thuật toán tạo và cung cấp một phần tử danh sách tại một thời điểm (một "trình vòng lặp") và làm việc với nó.

Có những thư viện tốt có thể làm điều đó (và nhiều hơn nữa), một số trong đó là Thuật toán :: Vòng lặp được đề xuất trong bài đăng trước về vấn đề này (và trong một nhận xét), Thuật toán :: Kết hợp (cùng nhận xét), Set::CrossProducttừ một câu trả lời khác đây ...

Cũng lưu ý rằng, trong khi đây là một cách sử dụng thông minh glob, thư viện có nghĩa là để làm việc với các tệp. Ngoài việc sử dụng sai về nguyên tắc, tôi nghĩ rằng nó sẽ kiểm tra từng tên (~ 12 triệu) cho một mục hợp lệ ! (Xem trang này .) Đó là rất nhiều công việc đĩa không cần thiết. (Và nếu bạn sử dụng "globs" như *hoặc ?trên một số hệ thống, nó sẽ trả về một danh sách chỉ có các chuỗi thực sự có tệp, vì vậy bạn sẽ lặng lẽ nhận được các kết quả khác nhau.)


 Tôi nhận được 56 byte cho một kích thước của một đại lượng vô hướng 5 char. Mặc dù đó là một biến được khai báo, có thể mất nhiều hơn một chút vô hướng, nhưng trong chương trình thử nghiệm có 4 chuỗi dài, tổng kích thước thực tế thực sự là một thứ tự lớn hơn lớn hơn so với biến được tính toán một cách ngây thơ. Vì vậy, thực tế có thể là theo thứ tự 1Gb, trong một hoạt động.

Cập nhật   Một chương trình thử nghiệm đơn giản tạo ra danh sách các chuỗi dài 5 ký tự (sử dụng cùng một globcách tiếp cận) đã chạy trong 15 phút trên máy lớp và chiếm 725 Mb bộ nhớ.

Nó đã tạo ra đúng số chuỗi dài 5 ký tự thực tế, dường như chính xác, trên máy chủ này.


@Gerry Trước tiên, tôi không chắc chắn rằng vấn đề là có giới hạn; nhìn vào nó ... Có lẽ tạo danh sách đầu tiên, lặp đi lặp lại (không phải tất cả cùng một lúc) và lưu trữ nó trong một mảng thích hợp? Điều đó chắc chắn sẽ không nhận được bất cứ nơi nào gần bất kỳ giới hạn nào, một "chuỗi" 5 ký tự. (Nó cũng được chẩn đoán --- nếu nó hoạt động thì đó thực sự là một giới hạn bên trong.)
zdim 16/11/19

@Gerry Đừng cần các mô-đun --- chỉ cần xây dựng danh sách (gồm các chuỗi năm ký tự) thành một mảng trước, từng mảnh một, thay vì gộp chúng lại với nhau bằng cách sử dụng glob. (Điều đó sẽ cần một số thuật toán đơn giản, đơn giản. Có lẽ những gì tôi đã đăng trong câu hỏi trước của bạn? Đó là cách gỡ lỗi tốt - nếu bạn có thể nhận được danh sách đó mà không gặp sự cố thì bạn biết rằng các giới hạn đang được đẩy ở đây.) Tôi đã thêm một số ước tính kích thước rằng tôi đang đến bài viết ...
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"... và để tôi kiểm tra ... bây giờ nó đã chạy trong 30 giây, điều gì xác nhận nó đưa ra cách thức hoạt động của bộ đệm ở đây. Tôi cũng đã kiểm tra RSS với các công cụ bên ngoài trong khi nó đang diễn ra.
zdim

@Gerry Tương tự hành vi trên v5.29.2 (~ 600Mb ngay bây giờ) ... vẫn cưỡi trên bộ đệm đó trên máy chủ này :)))
zdim

@Gerry Kết quả từ một máy lớp khác, với v5.16 - 28 phút (bị đánh giá thấp trong khi nó đang diễn ra!) Và 750Mb. Bây giờ chạy lại dưới 5.29.2 và một lần nữa ~ 600Mb. Chuỗi chính xác và số chính xác của chúng (chính xác 26**5)
zdim 16/11/19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.