[Perl]通过 pack 压缩运行时数组的体积,节省内存空间

There's more than one way to do it!
https://metacpan.org http://perlmonks.org
头像
523066680
Administrator
Administrator
帖子: 422
注册时间: 2016年07月19日 12:14
拥有现金: 锁定
储蓄: 锁定
Has thanked: 41 times
Been thanked: 64 times
联系:

[Perl]通过 pack 压缩运行时数组的体积,节省内存空间

帖子 #1 523066680 » 2019年02月03日 21:43

,
use Devel::Size qw/total_size/;
our ($a, $b, $c) = ([], [], '');
for my $idx ( 0 .. 2000000 )
{
'1'; push @$a, [0.5, 0.6, 0.8];
'2'; push @$b, pack("fff", 0.5, 0.6, 0.8);
'3'; $c .= pack('f3', 0.5, 0.6, 0.8 );
}

grep { printf "%s %.2f MB\n", $_, total_size(${"$_"})/1024**2 } ('a','b','c');

=result
a 298.87 MB
b 96.69 MB
c 25.08 MB
=cut

Devel::Size 是一个外部模块,用于检测某个容器的体积。
假设有一堆三维点阵数据,需要一次载入数组,为了方便会选用二维数组,通过数组引用的形式将 [x y z] 打包起来。
但是实测中发现内存很容易就爆满,特别是最初为了方便而使用哈希 {'x'=>0.5, 'y'=>'0.6', 'z'=>'0.8'},千万个坐标点秒秒钟 out of memory。

如果改用 pack 将数据打包,以二进制而不是字符串表面形式,push @$b, pack("fff", 0.5, 0.6, 0.8); 可以将体积压缩到1/3 (针对此例)
而如果使用字符串“流”的形式进行打包 $c .= pack('f3', 0.5, 0.6, 0.8 ),可将占用缩减到原来的 1/10 不到。
内存又宽松起来了 :)

头像
523066680
Administrator
Administrator
帖子: 422
注册时间: 2016年07月19日 12:14
拥有现金: 锁定
储蓄: 锁定
Has thanked: 41 times
Been thanked: 64 times
联系:

对 pack 过的二维数组进行排序

帖子 #2 523066680 » 2019年02月03日 21:44

在使用 pack 打包数据的情况下对二维数组排序。(以前写过一个普通版本的,参考:http://www.bathome.net/viewthread.php?tid=45306

最初的方案是在 sort { } 内嵌函数中使用 unpack 释放数据逐项对比(每次都unpack会产生冗余消耗)。
但细想似乎不需要unpack,由于每一个字段都是对齐的,可以直接按字符串对比,操作上反而简单了:

Code: [全选] [展开/折叠] [Download] (Untitled.bsh)
  1. =info
  2.     使用 pack 压缩数组的内存占用空间
  3.     二维不定长数组排序测试
  4.     523066680/vicyang
  5. =cut
  6. STDOUT->autoflush(1);
  7. srand(23);
  8. my @arr;
  9. print "Stage1\n";
  10. for (1 .. 20) {
  11.     push @arr, pack("L*", reverse sort { $a <=> $b } map { int(rand(15)) } ( 1 .. rand(8)+2 ) );
  12. }
  13.  
  14. print "Stage2\n";
  15. grep { print join(",", unpack "L*", $_ ),"\n" } reverse sort @arr;

14,14,10,9,1
14,13,9,8,8,7,4,2,2
14,10,8
14,8,7,4,3,3,3,0,0
14,8,1
13,13,13,13,9,8,6,4
13,11,9,7,7,6,2,1
13,10,7,0
13,9,8,7,5,1,1,1,0
12,12,11,6,6,6,4,4,2
12,11,6
12,10,2,2,2,0
12,6
11,10,1,0
11,9,9,1,1,0
11,4,3
10,9,7,0
9,8,7,7,6,3,3,3,1
7,7,4,1
6,3

(排序规则,以开头元素的数值优先排序,后面的其次,最后如果同列的数字都相等,按长度判定。)


回到 “Perl”

在线用户

用户浏览此论坛: 没有注册用户 和 0 访客