我想让我的Perl程序使用多个核心。它会逐步读取查询输入并将其与从文件加载到内存中的只读数据结构的块进行比较,用于每次运行。该数据结构通常为几千兆字节,是一组小C例程中使用的打包字符串。当进程被分叉时,所有内容都会被复制,这在多核机器上很快会使RAM耗尽。我尝试了几个非标准模块,但都导致速度变慢和/或RAM溢出。我认为,对于只读数据,Perl不需要坚持制作副本。其他语言可以做到。有人有什么想法吗?
Fork通常不会在修改之前复制内存(搜索copy on write或COW)。您确定您正在正确地测量内存使用情况吗?请从free的before/after值中减去,而不是使用top。
编辑-示例脚本
尝试使用以下设置运行以下内容: ./fork_mem_usage 5 10000 ./fork_mem_usage 25 10000 ./fork_mem_usage 5 100000 ./fork_mem_usage 25 100000
如果第一个增加比后续的增加更大,则fork正在使用写时复制。它几乎肯定是(当然除了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}');
}
我对threads::shared
是一个选项的想法非常错误。在线程创建时,即使是共享数据结构也会被复制。这确实很糟糕,因此我可以总结说,Perl完全无法进行内存密集型计算。
fork
时,内核会复制整个进程。驻留在RAM中的所有内容都会被复制。没有任何语言可以绕过这一点。但是,您可以尝试使用内存映射,或者您可以使用线程。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";
forks
模块模拟了旧版 Perl 的线程,因为它实际上与 threads
具有相同的 API。(您使用的是哪个 Perl 版本?)ForkManager
使用一个带有序列化数据结构的文件进行数据共享 - 这不是您想要的。Shareable
在内存中执行相同的操作,因此全局只有一个序列化数据结构和每个进程一个反序列化数据结构。threads::shared
真的应该解决您的问题。整个问题的一部分是 Perl 不像 C 一样在原始内存上运行,而是为您管理内存,并具有垃圾回收的好处。 - amon您可以使用Cache::FastMmap来存储共享数据。我听说有人将其用于IPC而不是缓存,这个缓存是在进程之间共享的。其中很大一部分是用C语言编写的。不要忘记在初始化时添加'raw_values=1'。可以压缩缓存中的值,因此如果您有足够的CPU和可压缩的数据,则可以节省大量内存。
它非常快,以下是一些基准测试:http://cpan.robm.fastmail.fm/cache_perf.html
由于Cache::FastMmap将一个共享文件映射到进程的内存空间中,这可能会使每个进程看起来相当大,即使它只是mmap'd内存,该内存在所有使用缓存的进程之间共享,并且甚至可能被交换出去,如果缓存使用率较低。
然而,操作系统会认为您的进程相当大,这可能意味着您之前设置的一些BSD::Resource或'ulimits'已经不再合理,因此请注意。