perl - 使用太多内存的整数数组?

时间:2011-06-22 13:33:36

标签: perl types

当我运行以下脚本时:

my @arr = [1..5000000];

for($i=0; $i<5000000; $i++) {
        $arr[$i] = $i;
        if($i % 1000000 == 0) {
                print "$i\n";
        }
}

它消耗大约500 MB的内存。用于高级编译语言我希望它大约是5M * 4B = 20MB(每个数字4个字节)。

我想这是因为每个值都是标量,而不是简单的二进制数。是否可以通过将这些值视为数字来减少内存占用量,或者仅以500 MB的速度执行此任务?

8 个答案:

答案 0 :(得分:4)

如果您正在处理此类大型数组,则可能需要使用the PDL之类的工具包。

(哦,是的,你是对的:它需要很多内存,因为它是一个Perl标量数组。)

答案 1 :(得分:3)

所有Perl值在内部表示为perl标量,它比简单的int消耗方式更多的内存。即使标量只持有int。即使标量是undef

正如其他人所建议的那样,如果你真的想要使用这种大型数组,可能需要考虑PDL

答案 2 :(得分:3)

你总是可以在Perl中使用C或C ++。这可能会让你在一些艰苦的工作中占用很少的空间。 只是一个使用C的想法!

#!/usr/bin/perl
use Inline C;
use strict;

for(my $i=0; $i<5000000; $i++) {
        set_array_index($i,$i);
        if($i % 1000000 == 0) {
                #print "$i\n";
                print get_array_index($i)."\n";
        }
}

__END__
__C__

int array[5000000];

void set_array_index(int index,int value) {
    array[index]=value;
}

int get_array_index(int index) {

    if (array[index]==NULL)
        return 0;

    return array[index];
}

答案 3 :(得分:2)

完整修改我的答案。看看你的代码中有什么,我看到了一些奇怪的东西。

my @arr = [1..5000000];

在此,您将匿名数组引用分配给$arr[0]。此数组仅包含一个值:数组引用。隐藏的匿名数组拥有500万个数字。

for($i=0; $i<5000000; $i++) {
        $arr[$i] = $i;
        if($i % 1000000 == 0) {
                print "$i\n";
        }
}

在这里,您将为数组填充500万个序列号,覆盖声明中的数组引用。

更短的方法是:

my @arr = (1 .. 5_000_000);

也许这会为你节省一些时间。

答案 4 :(得分:2)

以下是交互式pdl2会话中的几行,展示了如何操作 这可以使用基本的PDL结构来完成:

pdl> $arr = sequence(long, 5000000) + 1;  # create pdl data array (a.k.a. a piddle)

pdl> help vars                            # see, it is only ~19MB
PDL variables in package main::

Name         Type   Dimension       Flow  State          Mem
----------------------------------------------------------------
$arr           Long D [5000000]            P           19.07MB
$Pi          Double D []                   P            0.01KB

pdl> p which( $arr%1000000 == 0 )         # which returns indexes which are true
[999999 1999999 2999999 3999999 4999999]

请参阅在线PDL book PDL可以用于什么的很好的介绍。 PDL mailing lists是最好的 有关PDL使用和开发的信息来源。反应经常是 快速。

答案 5 :(得分:1)

您可以使用pack创建一个长度恰好为5000000 * 4个字符的二进制字符串,而不是创建数组:

my $numbers = "";
$numbers .= pack("N", $_) for (1..5000000);

绝对应该占用更少的空间。因此,您可以使用substrunpack来获取值。

答案 6 :(得分:1)

也许你可以使用迭代器而不是如此庞大的整数列表。

迭代器为每个新值支付函数调用的开销,但节省了内存。检查MJD高阶Perl第4章(4.2.1)。

如果我没记错的话,范围运营商不会在最新的perls中建立如此庞大的列表。

答案 7 :(得分:0)

或者,为您隐式处理包,有Tie::Array::PackedC

use Tie::Array::PackedC;
# make @arr use $arr_storage for storing packed elements, by default using 'l!' pack format
tie my @arr, 'Tie::Array::PackedC', my $arr_storage;

vec也可能是有意义的。