私のPerlプログラムに複数のコアを使用させたいと思います。クエリ入力を段階的に読み取り、実行ごとにファイルからメモリにロードされる読み取り専用のデータ構造とそのチャンクを比較します。そのデータ構造は、通常は数ギガバイトであり、小さなCルーチンで使用されるパックされた文字列の小さなセットです。プロセスがフォークされると、すべてがコピーされ、マルチコアマシンではRAMがすぐに消費されます。いくつかの非標準モジュールを試しましたが、すべてが遅くなったり、RAMが壊れたりします。読み取り専用データの場合、Perlはコピーの作成を主張しないだろうと思いました。他の言語でも可能です。誰かアイデアがありますか?
3 に答える
Fork は通常、メモリが変更されるまでメモリをコピーしません (copy on write または COW を検索してください)。メモリ使用量を正しく測定していますか? top を使用するのではなく、free から前後の値を減算します。
編集 - サンプルスクリプト
次のような設定で実行してみてください: ./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されたメモリであるにもかかわらず、各プロセスが非常に大きく見える可能性があります。キャッシュの使用率が低くなっています。
ただし、OSはプロセスが非常に大きいと見なします。これは、以前に設定したBSD ::Resourceまたは「ulimits」にヒットしたことを意味する場合があります。
編集と要約:
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
1 つのスレッドで更新されると、変更は他のスレッドにも伝搬されます。printステートメントを次のように置き換えると、これを見ることができます
print threads->tid, "-->", ++$sharedVariable, "\n";