我想在内存中创建和操作(4字节)整数的大数组.从大到大,我的意思是数亿.阵列中的每个细胞将充当染色体上位置的计数器.我所需要的只是让它适合内存,并快速(O(1))访问元素.我正在计算的东西不是稀疏特征,所以我不能使用稀疏数组.
我不能用常规的perl列表来做这个,因为perl(至少在我的机器上)每个元素使用64个字节,所以我使用的大多数生物的基因组都太大了.我已经尝试通过sqlite和哈希绑定将数据存储在磁盘上,尽管它们有效,但速度非常慢,特别是在普通驱动器上. (当我在4驱动器raid 0上运行时,它的工作原理相当不错).
我以为我可以使用PDL数组,b / c PDL就像C一样存储它的数组,每个元素只使用4个字节.但是,我发现与perl列表相比,更新速度极其缓慢:
use PDL; use Benchmark qw/cmpthese/; my $N = 1_000_000; my @perl = (0 .. $N - 1); my $pdl = zeroes $N; cmpthese(-1,{ perl => sub{ $perl[int(rand($N))]++; },pdl => sub{ # note that I'm not even incrementing here just setting to 1 $pdl->set(int(rand($N)),1); } });
返回:
Rate pdl perl pdl 481208/s -- -87% perl 3640889/s 657% --
有谁知道如何提高pdl set()的性能,或者知道可以实现这一目标的不同模块?
解决方法
我不知道你将获得什么样的性能,但我建议使用记录为
here的vec函数将字符串拆分为位字段.我已经进行了实验,发现我的Perl会容忍长达500_000_000个字符的字符串.对应于125,000,000个32位值.
my $data = "\0" x 500_000_000; vec($data,32)++; # Increment data[0] vec($data,100_000_000,32)++; # Increment data[100_000_000]
如果这还不够,可能会在Perl的构建中控制限制.或者,如果您认为可以获得更小的字段 – 例如16位计数 – vec将接受任何2到32的幂的字段宽度.
编辑:我认为字符串大小限制与32位Windows进程上2GB最大私有工作集相关.如果您运行Linux或拥有64位perl,您可能比我幸运.
我已经添加了这样的基准程序
my $vec = "\0" x ($N * 4); cmpthese(-3,1); },vec => sub { vec($vec,int(rand($N)),32)++; },});
给出这些结果
Rate pdl vec perl pdl 472429/s -- -76% -85% vec 1993101/s 322% -- -37% perl 3157570/s 568% 58% --
所以使用vec的速度是原生阵列的三分之二.据推测这是可以接受的.