我希望让我的Perl程序使用多个核心。它逐步读取查询输入,并将其中的块与每个运行的从文件加载的只读数据结构进行比较。该数据结构通常是几千兆字节,是一小组压缩字符串,用于小型C例程。当进程被分叉时,所有内容都被复制,这在多核计算机上快速打开RAM。我尝试了几个非标准模块,但都会导致速度变慢和/或破坏RAM。我认为,对于只读数据,Perl不会坚持要复制。其他语言可以做到。有没有人有想法?
答案 0 :(得分:2)
Fork通常不会复制内存,直到它被修改(在写入或COW上搜索副本)。您确定正确测量内存使用情况吗?从free中减去值之前/之后而不是使用top。
编辑 - 示例脚本
尝试使用以下设置运行以下内容: ./fork_mem_usage 5 10000 ./fork_mem_usage 25 10000 ./fork_mem_usage 5 100000 ./fork_mem_usage 25 100000
如果第一次增加大于后续增加,那么fork正在使用copy-on-write。几乎可以肯定的是(当然除了Windows)。
#!/usr/bin/perl
use strict;
use warnings;
my $num_kids = shift @ARGV;
my $arr_size = shift @ARGV;
print "$num_kids x $arr_size\n";
my @big_array = ('abcdefg') x $arr_size;
die "Array wrong length" unless ($arr_size == @big_array);
print_mem_usage('Start');
for my $i (1..$num_kids) {
my $pid = fork();
if ($pid) {
if ($i % 5 == 0) {
print_mem_usage($i);
}
}
else {
sleep(5);
exit;
}
}
print_mem_usage('End');
exit;
sub print_mem_usage {
my $msg = shift;
print "$msg: ";
system q(free -m | grep buffers/cache | awk '{print $3}');
}
答案 1 :(得分:0)
threads::shared
是一个选项,我一直非常错误。在创建线程时,甚至会复制共享数据结构。这确实很糟糕,因此我可以总结Perl完全无法进行内存密集型计算。
当进程fork
时,内核会复制整个进程。驻留在RAM中的所有内容都是重复的。没有语言可以解决这个问题。但是,您可以尝试内存映射,也可以使用线程。
Perl线程是fork
仿真,但您可以将变量声明为线程之间的共享:
use threads;
use threads::shared;
my $sharedVariable :shared = 0;
my @worker;
for my $i (1 .. 6) {
push @worker, threads->create(\&worker_sub);
}
$_->join() foreach @worker;
sub worker_sub {
sleep rand 5;
print $sharedVariable, "\n";
}
如果在一个线程中更新$sharedVariable
,则更改也会传播到其他线程。如果用
print threads->tid, "-->", ++$sharedVariable, "\n";
答案 2 :(得分:0)
您可以使用Cache :: FastMmap存储共享数据。我听说有人用这个用于IPC不用于缓存,并且这个缓存在进程之间共享。其中很大一部分是用C语言编写的。不要忘记在初始化中添加'raw_values = 1'。可以压缩缓存中的值,这样如果你有足够的CPU和数据压缩,它会给你带来很多内存。
速度非常快,这里有一些基准:http://cpan.robm.fastmail.fm/cache_perf.html
因为Cache :: FastMmap mmap是进程内存空间中的共享文件,这可以使每个进程看起来都很大,即使它只是在使用缓存的所有进程之间共享的mmap内存,甚至可能被交换如果缓存使用率很低,则输出。
然而,操作系统会认为你的过程非常大,这可能意味着你打了一些之前设定的BSD :: Resource或'ulimits',你认为它是理智的,但现在不是了,所以要注意。