我希望让我的 Perl 程序使用多个内核。它逐步读取查询输入,并将其中的块与每次运行时从文件加载到内存中的只读数据结构进行比较。该数据结构通常为几千兆字节,是一小组用于小型 C 例程的打包字符串。当进程分叉时,所有内容都会被复制,这在多核机器上会迅速耗尽 RAM。我尝试了几个非标准模块,但都导致运行缓慢和/或损坏 RAM。我认为,对于只读数据,Perl 不会坚持制作副本。其他语言可以做到。有人有想法吗?
3 回答
Fork 通常不会复制内存,直到它被修改(搜索 copy on write 或 COW)。您确定您正在正确测量内存使用情况吗?从 free 中减去之前/之后的值,而不是使用 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}');
}
您可以使用 Cache::FastMmap 来存储共享数据。听说有人用这个做IPC而不是缓存,这个缓存是进程间共享的。其中大部分是用 C 编写的。不要忘记在初始化时添加 'raw_values=1'。可以压缩缓存中的值,因此如果您有足够的 CPU 并且您的数据可压缩,它将为您节省大量内存。
它非常快,这里有一些基准:http ://cpan.robm.fastmail.fm/cache_perf.html
因为 Cache::FastMmap mmap 是一个共享文件到您的进程内存空间中,这会使每个进程看起来非常大,即使它只是在使用缓存的所有进程之间共享的 mmap 内存,如果缓存的使用率越来越低。
但是,操作系统会认为您的进程非常大,这可能意味着您遇到了一些您之前设置的 BSD::Resource 或“ulimit”,您认为这些是正常的,但现在不再存在,所以请注意。
编辑和总结:
threads::shared
关于成为一个选项,我是非常错误的。在创建线程时,甚至共享数据结构也会被复制。这确实很糟糕,因此我可以总结出 Perl 完全无法进行内存密集型计算。
当一个进程fork
s时,内核复制整个进程。驻留在 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 语句替换为
print threads->tid, "-->", ++$sharedVariable, "\n";