Perl 标量上下文中的glob是惰性迭代器吗?

Perl 标量上下文中的glob是惰性迭代器吗?,perl,Perl,我很喜欢它经常被忽略的迭代器式功能 我不清楚的是,即使在标量上下文中使用,它是否会计算/加载整个列表到内存中。在此示例代码中,while循环不会向屏幕打印任何内容(4**24不是一个小数字): 我试过/观察到的事情: 我试图通过编写1而glob$opt,但这仍然需要很长时间,最后我按Ctrl+C'ing组合键退出 当我运行脚本时,通过Windows任务管理器检查我的内存使用情况似乎没有显示任何差异 运行perl-MO=Deparse仅确认glob正在标量上下文中使用,而不指示任何内存使用情况

我很喜欢它经常被忽略的迭代器式功能

我不清楚的是,即使在标量上下文中使用,它是否会计算/加载整个列表到内存中。在此示例代码中,
while
循环不会向屏幕打印任何内容(4**24不是一个小数字):


我试过/观察到的事情:

  • 我试图通过编写
    1而glob$opt,但这仍然需要很长时间,最后我按Ctrl+C'ing组合键退出

  • 当我运行脚本时,通过Windows任务管理器检查我的内存使用情况似乎没有显示任何差异

  • 运行
    perl-MO=Deparse
    仅确认
    glob
    正在标量上下文中使用,而不指示任何内存使用情况

  • 运行
    perl-MO=concrete
    会产生以下输出,我不知道如何解密:

    m  <@> leave[1 ref] vKP/REFC ->(end)
    1     <0> enter ->2
    2     <;> nextstate(main 49 -:5) v:%,*,&,{,x*,x&,x$,$,469762048 ->3   
    7     <2> sassign vKS/2 ->8
    5        <2> repeat[t2] sK/2 ->6
    3           <$> const[PV "{A,B,C,D}"] s ->4
    4           <$> const[IV 24] s ->5
    6        <0> padsv[$opt:49,74] sRM*/LVINTRO ->7
    8     <;> nextstate(main 74 -:6) v:%,*,&,{,x*,x&,x$,$,469762048 ->9
    l     <@> leave vK* ->m
    9        <0> enter v ->a
    -        <1> null vKP/1 ->l
    g           <|> and(other->h) vK/1 ->l
    f              <1> defined sK/1 ->g
    e                 <2> sassign sK/2 ->f
    c                    <@> glob[t5] sK/1 ->d
    -                       <0> ex-pushmark s ->a
    a                       <0> padsv[$opt:49,74] s ->b
    b                       <#> gv[*_GEN_0] s ->c
    -                    <1> ex-rv2sv sKRM*/3 ->e
    d                       <#> gvsv[*_] s ->e
    -              <@> lineseq vK ->-
    j                 <@> say vK ->k
    h                    <0> pushmark s ->i
    -                    <1> ex-rv2sv sK/3 ->j
    i                       <#> gvsv[*_] s ->j
    k                 <0> unstack v ->a
    - syntax OK
    
    m leave[1 ref]vKP/REFC->(结束)
    1输入->2
    2下一状态(主49-:5)v:%,*,&,{,x*,x&,x$,$,469762048->3
    7设计vKS/2->8
    5重复[t2]sK/2->6
    3常数[PV{A,B,C,D}]s->4
    4常数[IV 24]s->5
    6 padsv[$opt:49,74]sRM*/LVINTRO->7
    8下一状态(主74-:6)v:%,*,&,{,x*,x&,x$,$,469762048->9
    l离开vK*->m
    9输入v->a
    -空vKP/1->l
    g和(其他->h)vK/1->l
    f定义的sK/1->g
    e sassign sK/2->f
    c全球[t5]sK/1->d
    -ex pushmark s->a
    a padsv[$opt:49,74]s->b
    b gv[*\u GEN\u 0]s->c
    -ex-rv2sv sKRM*/3->e
    d gvsv[*uUs]s->e
    -lineseq vK->-
    j说vK->k
    h推动标记s->i
    -ex-rv2sv sK/3->j
    i gvsv[*Us]s->j
    k取消堆叠v->a
    -语法正常
    

我正在运行ActivePerl 5.16.3。

当您观察到第一次全局调用和第一次打印结果之间的延迟时,它似乎并不懒惰。在标量上下文中而不是在循环中执行全局所需的时间进一步证实了这一点(在我的示例中,我使用了较小的指数,因此延迟仍然很明显,但不会太长):


当glob模式包含大括号时,将调用递归函数来展开大括号。请参阅Perl源代码*中的
ext/File glob/bsd_glob.c

/*
*递归地展开一个glob{}模式。当没有更多的展开时
*调用标准的globbing例程对其余的魔法进行glob
*人物
*/
静态整数
globexp1(常量字符*模式,glob_t*pglob)
{
常量字符*ptr=模式;
int-rv;
/*为find(1)保护单个{},如csh*/
如果(模式[0]==BG\U LBRACE和模式[1]==BG\U RBRACE和模式[2]==BG\U EOS)
返回glob0(模式,pglob);
while((ptr=(const Char*)g_strchr((Char*)ptr,BG_LBRACE))!=NULL)
if(!globexp2(ptr、模式、pglob和rv))
返回rv;
返回glob0(模式,pglob);
}
我的C已经生锈了,但是当我在gdb中运行你的脚本并在这个函数上设置一个断点时,它会被多次命中,这表明它是一个非常深层的递归,并且扩展为非惰性行为。希望更熟悉Perl内部结构的人能够详细说明



*上面是5.20.2版的。

很有趣。我本以为
glob
中隐含的是扩展模式的需要,但我想它只会
迭代当前文件系统以查找匹配项。@Sobrique:使用
-MO=concrete
进行检查会产生任何线索吗?我不知道如何进行交互pret操作码可能是,但我个人对它不够熟悉,无法理解。迭代器必须首先计算所有的组合,这让我感到很奇怪。我想我可以理解为什么在全局搜索文件系统时会这样做(
),似乎这种行为扩展到了只包含
{}的字符串
通配符。@Zaid事实上,我认为在“正常”情况下,所有的
{}
模式都会在查看文件系统之前展开:)@hobbs:您的陈述看起来会得到这个SuiteisBlacknot的确认。
m  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 49 -:5) v:%,*,&,{,x*,x&,x$,$,469762048 ->3   
7     <2> sassign vKS/2 ->8
5        <2> repeat[t2] sK/2 ->6
3           <$> const[PV "{A,B,C,D}"] s ->4
4           <$> const[IV 24] s ->5
6        <0> padsv[$opt:49,74] sRM*/LVINTRO ->7
8     <;> nextstate(main 74 -:6) v:%,*,&,{,x*,x&,x$,$,469762048 ->9
l     <@> leave vK* ->m
9        <0> enter v ->a
-        <1> null vKP/1 ->l
g           <|> and(other->h) vK/1 ->l
f              <1> defined sK/1 ->g
e                 <2> sassign sK/2 ->f
c                    <@> glob[t5] sK/1 ->d
-                       <0> ex-pushmark s ->a
a                       <0> padsv[$opt:49,74] s ->b
b                       <#> gv[*_GEN_0] s ->c
-                    <1> ex-rv2sv sKRM*/3 ->e
d                       <#> gvsv[*_] s ->e
-              <@> lineseq vK ->-
j                 <@> say vK ->k
h                    <0> pushmark s ->i
-                    <1> ex-rv2sv sK/3 ->j
i                       <#> gvsv[*_] s ->j
k                 <0> unstack v ->a
- syntax OK
use strict;
use warnings;
use feature 'say';
use Time::HiRes;

$| = 1;

my $opt = "{A,B,C,D}" x 10;
say Time::HiRes::time;
my $x = glob $opt;
say $x;
say Time::HiRes::time;
say while glob $opt;
say Time::HiRes::time;