2011-06-22 49 views
7

當我運行下面的腳本:perl - 使用太多內存的整數數組?

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?

+0

問題的一部分是'my @arr = [1..5000000];'是一個錯誤,不會做你想做的事情。如果你寫了'my @arr =(1..5000000);',你可能會看到更少的用法。或者只是'my @arr;',因爲你沒有使用任何你初始化的值。 – hobbs

+0

@hobbs - 我爲儘可能簡單的例子而做出的。我真正的腳本確實使用數組。 –

回答

4

如果您正在處理如此大的陣列,您可能需要使用一個工具包,如the PDL

(哦,是的,你是正確的:它需要這麼多的內存,因爲它是Perl的標量數組)。

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); 

也許可以救你的一些記憶。

+1

'[1..5_000_000]'無論是否爲常量,都會消耗盡可能多的內存。 – hobbs

+0

@hobbs好的,謝謝你的確認。 – TLP

1

而不是創建一個數組,你可以創建一個二進制字符串,這正是長期使用包5000000 * 4字符:

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

它絕對應該採取更小的空間。因此,您可以使用substrunpack來獲取值。

3

所有的Perl值在內部表現爲perl標量,它比簡單的int消耗方式更多的內存。即使標量只持有一個整數。即使標量是undef

正如其他人所建議的,如果您真的想要處理這種龐大的數組,可能需要查看PDL

+0

你需要24個字節來存儲一個Perl標量的整數值,更多的是一個字符串:http://codenode.com/perl-memory-usage/ – mob

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]; 
} 
1

也許你可以使用迭代器而不是這樣一個大整數列表。

迭代器爲每個新值支付函數調用的開銷,但會節省內存。檢查MJD高階Perl第4章(4.2.1)。

如果我記得它是正確的,範圍運算符不會'在最新的perls中創建這樣一個巨大的列表。

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也可能是感興趣。

+0

我剛剛讀過Tie :: Array :: PackedC文檔,它似乎是一個有趣的解決方案來保持內存使用率低 –

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使用和開發信息的來源。反應速度通常爲 。