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