将大值传递给模块

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 数据,因为它是“全局的”,在这样的我可以使用集中式子的一种方式。

ike*_*ami 7

您不能将数组传递给 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 的下一个主要版本中默认启用它,因此他们肯定认为它非常稳定。