perl goto&Name 对比 return
perl goto&Name vs return
我最近偶然发现了一段 perl 代码。代码如下所示
package CODE;
sub _doJob
{
$result = JOB->new(@_)->doIt();
return $result;
}
sub _doFirstJob
{
unshift @_, '1';
goto &_doJob;
}
sub _doSecondJob
{
unshift @_, '2';
goto &_doJob;
}
sub _doThirdJob
{
unshift @_, '3';
goto &_doJob;
}
然后调用
等函数
$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);
问题是这里的goto
有什么意义?如果我用 return
编写类似的函数调用,如下所示,会出现什么问题?
package CODE;
sub _doJob
{
$result = JOB->new(@_)->doIt();
return $result;
}
sub _doFirstJob
{
unshift @_, '1';
return &_doJob(@_);
}
sub _doSecondJob
{
unshift @_, '2';
return &_doJob(@_)
}
sub _doThirdJob
{
unshift @_, '3';
return &_doJob(@_)
}
我仍然可以用同样的方式调用这些函数
$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);
我知道 goto &NAME
实际上让 perl 退出当前函数并用调用堆栈中的新函数替换它。但是我在这里如何从中受益?
您可以通过跳过堆栈处理来节省一些时间和内存。您可以使用 Benchmark 来测试您的情况下差异是否显着。
阅读 "Tail Call" 也可能会提供一些信息。例如,在 PerlMonks.
查看这个旧线程
更新
我使用以下脚本进行了测试:
sub rec {
$_[0]++;
sleep 5, return if $_[0] > 1000;
return rec(@_); # Comment this line.
goto &rec
}
rec(1 .. 200);
时间差异无法衡量,内存消耗也大不相同:return
情况占用的字节数几乎是 goto
情况的两倍。随着迭代次数的增加,goto
的内存消耗保持不变,但随着 return
.
的增加而增加
不幸的是,尾巴调用神话只是一个神话。 goto 仍然会创建一个新的堆栈框架并且并不比递归快。我尝试用 cperl 消除这个成本,进行真正的尾递归,覆盖堆栈值,但我认为我还没有正确解决它。整个 ABI 是高度去优化的。而且它只适用于 cperl 签名,因为只有那些使用堆栈 ABI 作为 XS 的签名。使用纯 perl5,你和 python.
一样乱七八糟
我最近偶然发现了一段 perl 代码。代码如下所示
package CODE;
sub _doJob
{
$result = JOB->new(@_)->doIt();
return $result;
}
sub _doFirstJob
{
unshift @_, '1';
goto &_doJob;
}
sub _doSecondJob
{
unshift @_, '2';
goto &_doJob;
}
sub _doThirdJob
{
unshift @_, '3';
goto &_doJob;
}
然后调用
等函数$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);
问题是这里的goto
有什么意义?如果我用 return
编写类似的函数调用,如下所示,会出现什么问题?
package CODE;
sub _doJob
{
$result = JOB->new(@_)->doIt();
return $result;
}
sub _doFirstJob
{
unshift @_, '1';
return &_doJob(@_);
}
sub _doSecondJob
{
unshift @_, '2';
return &_doJob(@_)
}
sub _doThirdJob
{
unshift @_, '3';
return &_doJob(@_)
}
我仍然可以用同样的方式调用这些函数
$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);
我知道 goto &NAME
实际上让 perl 退出当前函数并用调用堆栈中的新函数替换它。但是我在这里如何从中受益?
您可以通过跳过堆栈处理来节省一些时间和内存。您可以使用 Benchmark 来测试您的情况下差异是否显着。
阅读 "Tail Call" 也可能会提供一些信息。例如,在 PerlMonks.
查看这个旧线程更新
我使用以下脚本进行了测试:
sub rec {
$_[0]++;
sleep 5, return if $_[0] > 1000;
return rec(@_); # Comment this line.
goto &rec
}
rec(1 .. 200);
时间差异无法衡量,内存消耗也大不相同:return
情况占用的字节数几乎是 goto
情况的两倍。随着迭代次数的增加,goto
的内存消耗保持不变,但随着 return
.
不幸的是,尾巴调用神话只是一个神话。 goto 仍然会创建一个新的堆栈框架并且并不比递归快。我尝试用 cperl 消除这个成本,进行真正的尾递归,覆盖堆栈值,但我认为我还没有正确解决它。整个 ABI 是高度去优化的。而且它只适用于 cperl 签名,因为只有那些使用堆栈 ABI 作为 XS 的签名。使用纯 perl5,你和 python.
一样乱七八糟