是返回的一个整体阵列从Perl子程序效率低下?
-
23-08-2019 - |
题
我经常有一个子程序,在Perl,填补一系列有一些信息。因为我还用于侵C++中,我发现自己常常这样做在Perl、使用参考文献:
my @array;
getInfo(\@array);
sub getInfo {
my ($arrayRef) = @_;
push @$arrayRef, "obama";
# ...
}
而不是更简单的版本:
my @array = getInfo();
sub getInfo {
my @array;
push @array, "obama";
# ...
return @array;
}
原因,当然,是的,我不想阵列可以在本地创建中子程序和随后复制上的回报。
是这样吗?或者不Perl优化,走呢?
解决方案
什么首先返回的数组引用?
sub getInfo {
my $array_ref = [];
push @$array_ref, 'foo';
# ...
return $array_ref;
}
my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};
根据dehmann的评论编辑:
它也可以在功能使用标准阵列,并返回一个引用。
sub getInfo {
my @array;
push @array, 'foo';
# ...
return \@array;
}
其他提示
传的引用是更有效的,但不同的是不一样大,如C ++。的参数值本身(这意味着:在阵列中的值)总是通过引用传递反正(返回值被复制虽然)
。问题是:什么关系呢?在大多数情况下,它没有。如果你回5元,不打扰了。如果你返回/传递100'000元素,使用引用。只有当它是一个瓶颈优化它。
如果我看看你的例子,想想你想做的事,我习惯了写这样的内容:
sub getInfo {
my @array;
push @array, 'obama';
# ...
return \@array;
}
在我看来,为的简单的版本的,当我需要返回大量数据。有没有需要的分配的外面,你在你的第一个代码段写,因为sub
为你做它my
阵列。反正你不应该做过早的优化,莱昂TIMMERMANS 的建议中。
要回答的最终反刍,没有,Perl不优化此远离。它不能,真的,因为返回一个数组并返回一个标量是根本不同的。
如果你正在处理大量的数据,或者如果性能是一个主要问题,那么你的C习惯会为你服务好 - 传递和返回到数据结构的引用,而不是自己,让自己不需要的结构被复制。但是,正如莱昂TIMMERMANS指出,绝大多数的时候,你用少量的数据和性能的处理是不是什么大不了的事,所以做的任何方式似乎最可读的。
这是我通常会返回一个数组的方式。
sub getInfo {
my @array;
push @array, 'foo';
# ...
return @array if wantarray;
return \@array;
}
这样,它一定会给你想要的方式,在标量或列表环境。
my $array = getInfo;
my @array = getInfo;
$array->[0] == $array[0];
# same length
@$array == @array;
我不会尝试,除非你知道它是你的代码的缓慢部分进行优化。即使这样我会用基准,以查看哪些子程序实际上更快。
有两个方面的考虑。最明显的一个就是你的数组有多大将得到?如果是小于几十元,那么大小不是一个因素(除非你是微优化对于一些快速调用的函数,但你必须做一些内存分析,证明第一)。
这是容易的部分。人们经常忽视的第二个考虑是接口。返回的数组将如何使用?这是重要的,因为整个数组语法是Perl有点儿可怕。例如:
for my $info (@{ getInfo($some, $args) }) {
...
}
这是难看。这是更好的。
for my $info ( getInfo($some, $args) ) {
...
}
它还适合于映射和grepping。
my @info = grep { ... } getInfo($some, $args);
但是,如果你要挑选出单个元件返回一个数组引用可以得心应手:
my $address = getInfo($some, $args)->[2];
这是更简单的比:
my $address = (getInfo($some, $args))[2];
或者:
my @info = getInfo($some, $args);
my $address = $info[2];
但在这一点上,你应该质疑@info是否是一个真正的列表或哈希值。
my $address = getInfo($some, $args)->{address};
你不应该做的是有getInfo()
返回标量上下文中的数组引用,并在列表环境的数组。此muddles传统使用标量上下文作为阵列长度的将用户惊喜。
最后,我将插入我自己的模块,方法::签名,因为它提供了一个折衷用于使在数组引用,而不必使用数组引用的语法。
use Method::Signatures;
method foo(\@args) {
print "@args"; # @args is not a copy
push @args, 42; # this alters the caller array
}
my @nums = (1,2,3);
Class->foo(\@nums); # prints 1 2 3
print "@nums"; # prints 1 2 3 42
这是通过数据::别名的魔术完成。
3其他潜在的巨大性能的改进如果你正在读一整个,相当大的文件和分片成阵列:
- 关闭缓冲sysread()代替阅读()(手册警告
关于混合)
- 预延长列通过重视的最后一个要素- 节省的存储拨款
- 使用Unpack()迅速分的数据,如uint16_t的图形数据通道
通过一系列参考的功能允许的主要程序来处理一个简单的阵列,同时写一旦忘工作人员的功能使用的更复杂的"$@"箭->[$二]访问的形式。很C'ish,它很有可能是快!
我什么都不知道Perl的,所以这是一个语言中立的答案。
有,在某种意义上说,没有效率的从子程序复制的阵列到调用程序。该低效率是在使用额外的内存以及将数据从一个地方复制到另一个所花费的时间。在另一方面,为所有,但最大的数组,你可能不给一个该死的,并且可能更喜欢复制阵列出高雅,cussedness或任何其他原因。
在有效的解决方案是为子程序通过调用程序的数组的地址。正如我说的,我还没有关于这方面的Perl的默认行为的线索。但是,一些语言提供程序员选择哪种方法的选项。