调用子程序的最快方法(Fastest way of calling a subroutine)

2019-08-16 19:37发布

据我所知,在Perl中,我们可以通过使用这些技术调用从模块子程序:

  • 出口子程序foo ,导入具有这个子程序模块。 最后把它在你的Perl脚本。
  • 创建一个Object在你的Perl脚本,模块的最后调用foo使用Object
  • 直接调用foo使用其路径,这样myDir::Module::foo();

如果我一直困惑,这是更好调用子程序的方法foo 。 如果我有一个动态脚本,这是我从浏览器中运行,而不是命令行,这接近一个应该去这样脚本花费较少的时间。

谢谢。

Answer 1:

还有就是最快的,并调用代码在Perl的最佳方式之间的差异。


编辑:请参阅simbabques回答为好。 他特别涵盖之间#1和#3,为什么你会使用任何的差异。


#1,#3:函数调用

你的#1和#3是相同的:子程序在全局可见的命名空间有一个独特的名字。 许多名字可以通过别名映射到一个子程序,或导入模块。

如果要调用在编译时已知函数的名称,子将在编译时得到解决。 这里假设你不自发地重新定义的功能。 如果确切功能在运行时才知道,这仅仅是一个哈希查找了。

有三种方法的功能如何可以被称为:

foo(@args);
&foo(@args);
@_ = @args; goto &foo;

数字一(括号有时可选)是默认,并验证你对原型子参数(不使用原型)。 此外,整个调用堆栈帧(具有许多有用的调试信息)被构造。 这需要时间。

排名第二跳过protoype验证,并假定你知道自己在做什么。 这稍快。 我认为这是草率的风格。

排名第三的是一个尾调用。 这将返回从返回值当前子foo 。 这是速度快,因为原型被忽略,并且当前调用堆栈帧可重复使用。 这是没有用的,很多时候,并有丑陋的语法。 内嵌代码是约一个数量级的速度(即在Perl中,我们更喜欢在循环递归☹)。

#2:方法调用

OO的灵活性是一个沉重的性价比:如您拨打上从来不知道,直到运行时消息的对象的类型,实际的方法只能在运行时解决。

这意味着, $foo->bar()查找功能bar ,该包装$foobless编辑成。 如果它不能在那里找到,它会搜索在父类。 这是缓慢的。 如果你想使用OO,注意浅的层次结构(→少的查询)。 难道还注意到,皮尔斯默认方法解析顺序是不寻常的。

你一般不能减少方法调用一个函数调用,即使你知道的类型。

如果$foo ,如果类的FooFoo::bar是一分,然后Foo::bar($foo)将跳过方法resultution,甚至可能会奏效。 然而,这打破了封装,将打破一度Foo是子类。 另外,如果这不起作用Foo没有定义bar ,但在父类中定义的方法。

我一般是倾向于面向对象的,直到其与基准,这将不会提供您所需要的性能清晰。



Answer 2:

  • 出口子程序FOO,导入具有这个子程序模块。 最后把它在你的Perl脚本。

为了做到这一点,你将使用出口商在模块/ package实现了分。 你告诉你的模块是什么将通过出口@EXPORT_OK@EXPORT 。 如果您use的模块,东西被导入到在编译时你当前的命名空间。 下面以语句是等价的。

# This is the same...
use Module;
# ... as this

BEGIN {
  require Module;
  Module->import();
}

你想,如果你有东西,你要在你的主脚本中使用,或者你要经常使用做到这一点。 一些例子是列表::的Util , 数据::自卸车或use feature 'say' 。 当然,你也可以在其他模块中使用它。

use Data::Dumper;
use List::Util qw(max);
use feature qw(say);

my @foo = (1, 2, 3, 4, 5, 23);
print Dumper \@foo;
say max(@foo);

美中不足的是,在这里,你“污染”的命名空间。 如果你必须这样做,但请记住,它发生在编译时,所以它是不是条件 。 你不能说

if ($foo) {
  use Some::Module 'foo';
  foo($foo);
} else {
  use Something::Else 'bar';
  bar();
}

这将同时加载Some::Module Something::Else在编译时间,从而提高您的程序所消耗的时间和内存。 该条件将工作过程中的,但它是没有效率的。

  • 在你的perl脚本创建模块的对象使用该对象最后调用foo。

这是面向对象的方法。 它是(如上所述)不compairable到其他方法。 你并不需要导入对象的方法。 您只需加载你的类(这是一个模块)或者与userequire (见上文),创建一个实例,并使用它的方法根据自己的喜好。 但是,你需要的是一个面向对象的模块。 如果您在如何工作的interestend,通过采取一看开始perlootut 。

  • 直接调用foo使用其路径,这样MYDIR ::模块:: foo的();.

它实际上不是其相当的路径,而是它的名字(空间)。 例如,数据::自卸车是Dumper.pm所在的文件夹Data ,在某个地方lib目录。 但是,这并不重要。

第一种方法的主要区别是,你ommit进口部分。 如果你想建立的东西,有条件地加载某些模块这是有用的,或者如果你是在一个巨大的(也许遗留)应用程序,不想污染命名空间。

if ($order_has_some_condition) {
  require Very::Long::NameSpace::For::This::Condition::Module;
  Very::Long::NameSpace::For::This::Condition::Module::do_stuff_with_an_order($order);
}

想象一下,这段代码是在传统子带2k行和很多东西怎么回事,大部分是从来没有在我们的情况下调用。 我们不希望use我们的模块,使其可用于每个了在这个庞大的代码来处理的,也许100不同的情况。 相反,我们希望如果我们真的需要它来只加载它。 现在,我们require的模块,并调用它使用全名子直接。

在conclusing,第一和第三种方式有其可取之处。 他们都需要存在,并且它们都应该在适当使用。 在某些情况下,它只是味道,但在另一些有意义的决定。 第二,面向对象,方法完全是另一回事。

有没有真正的速度差异,并作为鲍罗廷说,Perl是快。 当然,如果你不import的东西,你不必为进口“买单”。 在10班轮脚本,这并不重要。 在与潜在的成千上万的一个巨大的文件,代码和许多用例的行传统的软件,这是相当重要的。

我希望这可以帮助你决定。



文章来源: Fastest way of calling a subroutine