如何内联 Perl 子例程?

发布于 2024-09-29 22:05:10 字数 343 浏览 8 评论 0原文

我正在阅读Code Complete 2,其中提到的一点是关于创建子例程,即使是对于看似的操作太简单了,没有自己的子例程,这会有什么帮助。

我知道我可以使用 inline 关键字C 和 C++ 中的内联函数。但我从未遇到过在 Perl 中内联子例程的方法。

有没有办法告诉 Perl 解释器内联子例程调用(或者为什么不)?

I am reading Code Complete 2, and one of the points mentioned is about creating subroutines even for operations that seem too simple to have their own subroutines, and how that can be helpful.

I know I can inline functions in C and C++ using the inline keyword. But I never came across a way to inline subroutines in Perl.

Is there a way to tell the Perl interpreter to inline the subroutine calls (or why not)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冷情 2024-10-06 22:05:10

常量子例程,即具有空原型和常量返回值的子例程,是内联的。这就是 constant 编译指示定义常量的方式:

sub five() { 5 }

如果在第一次使用之前看到它,则它将被内联。

否则,Perl 允许在运行时动态重新定义子例程,因此内联不适合。

对于在给定相同输入的情况下始终返回相同值的子例程,您可以使用记忆化

《Perl 编程》第 13 章 提供了有关所采取的优化步骤的一些信息由 Perl 编写。

这称为常量折叠。常量折叠并不限于简单的情况,例如在编译时将 2**10 转换为 1024。它还解析函数调用——满足第 6 章子例程中“内联常量函数”部分的标准的内置子例程和用户声明的子例程。让人想起 FORTRAN 编译器对其自身内在函数的臭名昭著的了解,Perl 也知道在编译期间要调用哪些自己的内置函数。这就是为什么如果您尝试取 0.0 的对数或负常量的 sqrt,您将引发编译错误,而不是运行时错误,并且解释器根本不会运行。

另请参阅 perldoc perlguts

您可以自己看到常量折叠的效果:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 1 }

if ( log_ok ) {
    warn "log ok\n";
}
perl -MO=Deparse t.pl

输出:

sub log_ok () { 1 }
use warnings;
use strict 'refs';
do {
    warn "log ok\n"
};
t.pl syntax OK

这里,常量折叠导致用 do 块替换 if 块,因为编译器知道 >log_ok 总是返回一个真值。另一方面,使用:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 0.5 > rand }

if ( log_ok ) {
    warn "log ok\n";
}

Deparse 输出:

sub log_ok () {
    use warnings;
    use strict 'refs';
    0.5 > rand;
}
use warnings;
use strict 'refs';
if (log_ok) {
    warn "log ok\n";
}
t.pl syntax OK

C 编译器可能已将 if (log_ok) 替换为 if ( 0.5 > rand )perl 不这样做。

Constant subroutines, i.e. subroutines with an empty prototype and constant return value, are inline. That is how the constant pragma defines constants:

sub five() { 5 }

would be inlined if it is seen before its first use.

Otherwise, Perl allows subroutines to be dynamically redefined at run time, so inlining is not suitable.

For subroutines that always return the same value given the same inputs, you can use memoization.

Chapter 13 of Programming Perl provides some information on the optimization steps taken by perl.

This is called constant folding. Constant folding isn't limited to simple cases such as turning 2**10 into 1024 at compile time. It also resolves function calls -- both built-ins and user-declared subroutines that meet the criteria from the section "Inlining Constant Functions" in Chapter 6, Subroutines. Reminiscent of FORTRAN compilers' notorious knowledge of their own intrinsic functions, Perl also knows which of its own built-ins to call during compilation. That's why if you try to take the log of 0.0 or the sqrt of a negative constant, you'll incur a compilation error, not a run-time error, and the interpreter is never run at all.

See also perldoc perlguts.

You can see the effect of constant-folding yourself:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 1 }

if ( log_ok ) {
    warn "log ok\n";
}
perl -MO=Deparse t.pl

Output:

sub log_ok () { 1 }
use warnings;
use strict 'refs';
do {
    warn "log ok\n"
};
t.pl syntax OK

Here, constant folding led to the replacement of the if block with a do block because the compiler knew that log_ok would always return a true value. On the other hand, with:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 0.5 > rand }

if ( log_ok ) {
    warn "log ok\n";
}

Deparse output:

sub log_ok () {
    use warnings;
    use strict 'refs';
    0.5 > rand;
}
use warnings;
use strict 'refs';
if (log_ok) {
    warn "log ok\n";
}
t.pl syntax OK

A C compiler might have replaced the if (log_ok) with if ( 0.5 > rand ). perl does not do that.

┼── 2024-10-06 22:05:10

Perl 只允许内联常量函数。来自 perldoc perlsub

原型为 () 的函数是
内联的潜在候选者。如果
优化后的结果和
常数折叠要么是一个常数
或一个词法范围的标量
没有其他参考,那么就可以了
用于代替函数调用
没有 & .

Perl only allows to inline constant functions. From perldoc perlsub:

Functions with a prototype of () are
potential candidates for inlining. If
the result after optimization and
constant folding is either a constant
or a lexically-scoped scalar which has
no other references, then it will be
used in place of function calls made
without & .

笑,眼淚并存 2024-10-06 22:05:10

我还没有尝试过这些,但如果你有时间,你可以尝试

  1. Macro< /code>
  2. 甚至 Filter::Macro

它们都是源过滤器,所以你'您必须检查您的绩效投资回报。
最后一篇实际上对 cpan ratings 进行了评论。 (忽略 Dan Dascalescu 试图规范 Perl 模块“空域”。)

-- 实际上,最后一个 Filter::Macro 使用 Filter::Simple::Compile (依次使用 Module::Compile) 来编译例程,因此这可能会在其他源过滤器方法之上执行。但是标准警告对源过滤器适用。

I haven't tried any of these, but if you have the time, you could try

  1. Macro
  2. macro
  3. or even Filter::Macro

They're all source filters so you'll have to check your return on investment in performance.
The last actually has a review on cpanratings. (Ignore Dan Dascalescu's attempt to regulate the Perl module "airspace".)

-- Actually, the last one Filter::Macro uses Filter::Simple::Compile (which in turn uses Module::Compile) to compile the routines, so this might perform above the other source filter methods. But the standard caveats on source filters apply.

永言不败 2024-10-06 22:05:10

编写 Perl 时,速度可能不应该成为考虑因素。继续让事情发挥作用。如果稍后的分析显示您由于频繁调用一个简单函数而花费了大量时间,那么您可以自己内联该函数。

Speed should probably not be a consideration when writing Perl. Go ahead and make things functions. If profiling later shows that you are spending a lot of time in a simple function due to calling it a lot, then inline that function yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文