Perl';地球仪有限制吗?

Perl';地球仪有限制吗?,perl,Perl,我正在运行以下5个字符的预期返回字符串: 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"; } anbc anbd anbe anbf anbg ... 但它只返回4个字符: 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"; } anbc

我正在运行以下5个字符的预期返回字符串:

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";
}
anbc
anbd
anbe
anbf
anbg
...
但它只返回4个字符:

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";
}
anbc
anbd
anbe
anbf
anbg
...
但是,当我减少列表中的字符数时:

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

aamid
aamie
aamif
aamig
aamih
...
有人能告诉我我在这里遗漏了什么吗?有某种限制吗?还是有办法解决这个问题


如果有任何不同,它将在
Perl5.26
Perl5.28
中返回相同的结果
glob
首先创建所有可能的文件名扩展,因此它将首先从给定的shell样式glob/模式生成完整的列表。只有这样,如果在标量上下文中使用,它才会对其进行迭代。这就是为什么在不耗尽迭代器的情况下逃离迭代器是如此困难(不可能?);看

在第一个示例中,有265个字符串(
11_881_376
),每个字符串长5个字符。因此,一个约1200万个字符串的列表,其(原始)总数超过56Mb。。。加上标量的开销,我认为至少是12字节左右。因此,至少在一个列表中有100Mb的数量级。†

我不知道Perl中对事物长度的任何正式限制(regex除外),但是
glob
在内部执行所有这些操作,并且必须有未记录的限制——也许某些缓冲区在内部某个地方溢出了?这有点过分

作为一种解决方法——迭代生成5字符字符串列表,而不是让
glob
在幕后发挥其魔力。那绝对不应该有问题

然而,我发现整个事情有点大的舒适,即使在这种情况下。我真的建议编写一个算法,一次生成并提供一个列表元素(“迭代器”),并使用它

有一些很好的库可以做到这一点(还有很多),其中一些是在之前关于这个问题的帖子(以及在评论中)中推荐的,(相同的评论),
Set::CrossProduct
,来自这里的另一个答案

还要注意的是,虽然这是对
glob
的巧妙使用,但该库是用来处理文件的。除了原则上误用它之外,我认为它还会检查每个(1200万)名字的有效条目!(请参阅。)这是大量不必要的磁盘工作。(如果在某些系统上使用像
*
这样的“globs”,它会返回一个列表,其中只包含实际有文件的字符串,因此您会悄悄地得到不同的结果。)


† 对于一个5字符的标量,我得到了56个字节。虽然这是一个声明的变量,可能比匿名标量多一点,但在长度为4个字符串的测试程序中,实际的总大小确实比原始计算的大一个数量级。因此,在一次操作中,真正的东西很可能在1Gb左右

Update一个简单的测试程序(使用相同的
glob
方法)在服务器级机器上运行了15分钟,占用了725MB的内存


它确实在这台服务器上生成了正确数量的实际5字符长字符串,看起来似乎是正确的。

一切都有一些限制

这里有一个纯Perl模块,它可以迭代地为您完成这项工作。它不会一次生成整个列表,您会立即得到结果:

use v5.10;

use Set::CrossProduct;

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

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

@首先,我不确定问题是否在于限制;调查一下。。。也许首先以迭代方式(不是一次生成全部)生成列表,并将其存储在适当的数组中?这肯定不会接近任何限制,一个“少量”的5字符字符串。(它也是诊断性的——如果它起作用,那么它确实是一些内部限制。)@Gerry不需要模块——只需先将列表(由五个字符字符串组成)逐段构建到数组中,而不是使用
glob
将其集总在一起。(这需要一些头脑简单的其他算法。也许我在你上一个问题中发布了什么?这是一个很好的调试——如果你可以毫无问题地获得该列表,那么你就知道限制正在被推到这里。)我添加了一些大小估计,我将要发布…@Gerry
time perl-MDevel::size=total_size-wE'$chs=join',,,“a”..“z”@items=glob“{$chs}”x5;说STDERR“总内存:”,总大小(\@items)/(1024**2),“Mb”
。。。让我查一下。。。现在它在30秒内运行,根据这里的缓存工作原理,什么证实了它。在RSS运行时,我还使用外部工具检查了它。@Gerry在v5.29.2(现在约600Mb)上也有相同的行为。。。仍然在这台服务器上的缓存上:)@gery来自另一台服务器级机器,版本为v5.16——28分钟(运行时被低估了!)和750Mb。现在在5.29.2下重新运行,然后再次运行~600Mb。正确的字符串和正确的字符串数量(准确地说是
26**5
):使用提供迭代器的模块,而不是滥用glob函数。谢谢@daxim。问题是我现在正在努力加载任何类型的模块,我有一个cpan问题,抱怨Win32::Console,但是ppm在perl 5.28中也不可用,所以我可以加载模块,让cpan停止抱怨。感谢@zdim感谢所有的时间和努力。我刚刚意识到。。。你到底想要这个随机列表,还是只想要一个完整的列表?@zdim只是一个完整的列表。:)伙计,你不明白我现在有多幸福。非常感谢你!!算法::循环的
NestedLoops
也可以使用:
使用算法::循环qw(NestedLoops);嵌套循环([(['a'..'z'])x5],子{比如连接',@})(OP对前面一个问题的回答提到,如果内存不足,他们可以使用此选项…)