Ric*_*k S 4 arrays perl module subroutine
我有一个很慢的程序,正在尝试提高性能。脚本在模块中“使用”sa sub,并将一个非常大的数组传递给 sub。经过一番修修补补,我意识到如果我将 sub 直接移动到父脚本中,并使数组全局而不是本地(所以我不必传递它),脚本会快得多(在几分钟内运行)天)。
我真的很希望能够在模块中包含该子程序(因为我有许多调用相同子程序的脚本)。但我也希望它快。:-)
半伪代码
页面.pl:
package Page;
use Star;
my @fileBytes=();
open(StarFile, "<$File");
binmode(StarFile);
while (read(StarFile, $FileValues, 1)) {
push @fileBytes, $FileValues;
}
close(StarFile);
&parseBlock(\@fileBytes);
Run Code Online (Sandbox Code Playgroud)
模块.pl:
package Star;
sub parseBlock {
my ($fileBytes) = @_;
my @fileBytes = @{ $fileBytes };
...
}
Run Code Online (Sandbox Code Playgroud)
在这里阅读一些内容:https : //www.perlmonks.org/? node = Variable%20Scoping%20in%20Perl%3A%20the%20basics 告诉我我想处理范围。因此,如果我使用“我们的”而不是“我的”来定义 @fileBytes,它将成为一个包值。据我所知,这通常在模块文件中。但我从父级的值开始。
所以我可以让父级也是一个包,定义:我们的@fileBytes
然后从模块中引用它至少像这样:@Page::fileBytes
我想我至少在理论上是正确的。
当我想使用来自不同脚本的 sub 时出现我的问题:
其他.pl:
package Other;
use Star;
my @fileBytes=();
open(StarFile, "<$File");
binmode(StarFile);
while (read(StarFile, $FileValues, 1)) {
push @fileBytes, $FileValues;
}
close(StarFile);
&parseBlock(\@fileBytes, $offset);
Run Code Online (Sandbox Code Playgroud)
现在我传递的值是 @Other::fileBytes 。我使用图书馆的次数越多,这个问题就会扩大。
我希望能够做的是在模块中有子例程,但不必传递(我认为这是创建一个新值,必须很慢)@fileBytes 数据,因为它是“全局的”,在这样的我可以使用集中式子的一种方式。
您不能将数组传递给 subs,只能传递标量。当一个使用 时f(@a),一个是传递数组的元素。这不会创建任何新标量或复制任何标量,因此它实际上仍然非常快。
然而,即使是那么小的成本也可以避免。这是通过对数组的引用来完成:f(\@a)。这确实创建了一个标量,但它是所有标量中最轻的。
这是您已经在做的事情,因此从调用 sub 的角度来看,您已经拥有最快的速度。您面临的问题是在调用 sub 后立即执行的操作的结果:您创建一个新数组并将所提供数组的每个元素复制到这个新数组中。
my @fileBytes = @{ $fileBytes }; # Copies every element.
Run Code Online (Sandbox Code Playgroud)
删除该行,您的问题就解决了。当然,您需要将使用重复数组 ( @fileBytes) 的任何代码更改为使用原始数组 ( @$fileBytes)。唯一需要注意的是,对数组的任何更改都将反映在通过对 sub 的引用传递的数组中,因为它是同一个数组。
替代方案
如果您坚持避免使用引用,则可以使用以下方法:
use experimental qw( declared_refs );
my \@fileBytes = $fileBytes;
Run Code Online (Sandbox Code Playgroud)
有效地@fileBytes为@$fileBytes. 不涉及复制。它不是免费的,但也不贵(O(1))。就像@$filesBytes直接修改一样,修改@fileBytes会影响调用者中的数组。
一般来说,应该避免在生产中使用实验性代码,但开发人员计划在 Perl 的下一个主要版本中默认启用它,因此他们肯定认为它非常稳定。