2011-06-22 26 views
7

Khi tôi chạy kịch bản sau đây:perl - mảng các số nguyên sử dụng quá nhiều bộ nhớ?

my @arr = [1..5000000]; 

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

Nó tiêu thụ khoảng 500 MB bộ nhớ. Được sử dụng cho các ngôn ngữ biên dịch cấp cao hơn, tôi hy vọng nó sẽ là khoảng 5M * 4B = 20MB (4 byte cho mỗi số).

Tôi đoán đó là vì mỗi giá trị là một vô hướng, không phải là số nhị phân đơn giản. Có thể giảm dung lượng bộ nhớ bằng cách xử lý các giá trị đó dưới dạng số hay 500 MB cho tác vụ này theo cách duy nhất không?

+0

Một phần của vấn đề là 'my @arr = [1..5000000];' là một sai lầm và không làm những gì bạn muốn. Bạn có thể thấy ít sử dụng hơn nếu bạn viết 'my @arr = (1..5000000);'. Hoặc đơn giản là 'my @arr;' vì bạn không sử dụng bất kỳ giá trị nào bạn khởi tạo. – hobbs

+0

@hobbs - Tôi đã tạo ra ví dụ đơn giản nhất có thể. Kịch bản thực sự của tôi không sử dụng mảng. –

Trả lời

4

Nếu bạn đang xử lý các mảng lớn như vậy, bạn có thể muốn sử dụng bộ công cụ như the PDL.

(Oh, và có, bạn là chính xác: Phải mất rất nhiều bộ nhớ bởi vì nó là một mảng vô hướng Perl.)

2

Hoàn chỉnh câu trả lời của tôi. Nhìn vào những gì bạn có trong mã của bạn, tôi thấy một số điều kỳ lạ.

my @arr = [1..5000000]; 

Tại đây, bạn chỉ định tham chiếu mảng ẩn danh cho $arr[0]. Mảng này chỉ chứa một giá trị: Tham chiếu mảng. Mảng ẩn danh ẩn chứa 5 triệu con số.

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

Tại đây, bạn điền mảng với 5 triệu số liên tiếp, ghi đè tham chiếu mảng trong khai báo.

Một cách ngắn hơn nhiều để làm điều đó sẽ là:

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

Có lẽ đó sẽ giúp bạn tiết kiệm một số bộ nhớ.

+1

'[1 .. 5_000_000]' tiêu thụ chính xác nhiều bộ nhớ cho dù đó là hằng số hay không. – hobbs

+0

@hobbs Ok, cảm ơn bạn đã xác nhận điều đó. – TLP

1

Thay vì tạo ra một mảng, bạn có thể tạo ra một chuỗi nhị phân đó là chính xác 5000000 * 4 ký tự sử dụng gói:

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

Nó chắc chắn nên mất ít không gian. Do đó, bạn có thể tìm nạp các giá trị với substrunpack.

3

Tất cả giá trị Perl được biểu thị nội bộ dưới dạng vô hướng perl, tiêu thụ cách nhiều bộ nhớ hơn một int đơn giản. Ngay cả khi vô hướng chỉ giữ một int. Ngay cả khi vô hướng là undef!

Như những người khác đã đề xuất, PDL có thể là một cái gì đó để xem xét nếu bạn thực sự muốn làm việc với mảng lớn của loại này.

+0

Bạn cần 24 byte để lưu trữ một giá trị số nguyên trong một vô hướng Perl, nhiều hơn cho một chuỗi ký tự: http://codenode.com/perl-memory-usage/ – mob

3

Bạn luôn có thể sử dụng C hoặc C++ trong Perl.Điều này có thể sẽ cung cấp cho bạn một dấu chân nhỏ trong một số công việc khó khăn. Chỉ cần một ý tưởng sử dụng 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

Có thể bạn có thể sử dụng trình lặp thay vì danh sách số nguyên lớn như vậy.

Trình vòng lặp trả tiền cho một cuộc gọi hàm cho mỗi giá trị mới, nhưng tiết kiệm bộ nhớ. Kiểm tra thứ tự cao hơn của MJD Perl Chương 4 (4.2.1).

Nếu tôi nhớ đúng, toán tử phạm vi không xây dựng danh sách lớn như vậy trong những lọn tóc mới nhất.

0

Hoặc ngầm xử lý các gói cho bạn, có 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 cũng có thể quan tâm.

+0

Tôi vừa đọc Tie :: Array :: PackedC documentation và it có vẻ là một giải pháp thú vị để giữ mức sử dụng bộ nhớ thấp. –

2

Dưới đây là một vài dòng từ một pdl2 phiên tương tác thể hiện như thế nào này có thể được thực hiện bằng cơ bản PDL xây dựng:

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] 

Xem trực tuyến PDL book cho một giới thiệu tốt để những gì PDL có thể được sử dụng cho. PDL mailing lists là nguồn thông tin tốt nhất về sử dụng và phát triển PDL. Câu trả lời thường là nhanh chóng .

Các vấn đề liên quan