必要な PDL コマンドはindadd
. (別の場所で指摘してくれた PDL Pumpking の Chris Marshall に感謝します。)
PDL は、私が「ベクトル化された」操作と呼ぶもののために設計されています。C 操作と比較して、Perl 操作は非常に遅いため、PDL メソッド呼び出しの数を最小限に抑え、各呼び出しで多くの作業を実行する必要があります。たとえば、このベンチマークでは、一度に実行する更新の数を (コマンドライン パラメータとして) 指定できます。perl 側はループする必要がありますが、PDL 側は 5 つほどの関数呼び出ししか実行しません。
use PDL;
use Benchmark qw/cmpthese/;
my $updates_per_round = shift || 1;
my $N = 1_000_000;
my @perl = (0 .. $N - 1);
my $pdl = zeroes $N;
cmpthese(-1,{
perl => sub{
$perl[int(rand($N))]++ for (1..$updates_per_round);
},
pdl => sub{
my $to_update = long(random($updates_per_round) * $N);
indadd(1,$to_update,$pdl);
}
});
これを引数 1 で実行すると、 を使用した場合よりもさらにパフォーマンスが低下しますset
。これは予想どおりです。
$ perl script.pl 1
Rate pdl perl
pdl 21354/s -- -98%
perl 1061925/s 4873% --
それは補うべき多くの根拠です!しかし、そこで我慢してください。ラウンドごとに 100 回の反復を行うと、改善が得られます。
$ perl script.pl 100
Rate pdl perl
pdl 16906/s -- -18%
perl 20577/s 22% --
また、1 ラウンドあたり 10,000 回の更新で、PDL は Perl よりも 4 倍優れています。
$ perl script.pl 10000
Rate perl pdl
perl 221/s -- -75%
pdl 881/s 298% --
PDL は、値がさらに大きい場合でも、プレーンな Perl よりも約 4 倍速く実行し続けます。
より複雑な操作では、PDL のパフォーマンスが低下する可能性があることに注意してください。これは、PDL が中間操作のために大規模で一時的なワークスペースを割り当てて破棄するためです。その場合は、 の使用を検討してInline::Pdlpp
ください。ただし、これは初心者向けのツールではないため、自分にとって本当に最適なツールであると判断するまで、そこに飛び込まないでください。
このすべてに代わる別の方法は、次のInline::C
ように使用することです。
use PDL;
use Benchmark qw/cmpthese/;
my $updates_per_round = shift || 1;
my $N = 1_000_000;
my @perl = (0 .. $N - 1);
my $pdl = zeroes $N;
my $inline = pack "d*", @perl;
my $max_PDL_per_round = 5_000;
use Inline 'C';
cmpthese(-1,{
perl => sub{
$perl[int(rand($N))]++ for (1..$updates_per_round);
},
pdl => sub{
my $to_update = long(random($updates_per_round) * $N);
indadd(1,$to_update,$pdl);
},
inline => sub{
do_inline($inline, $updates_per_round, $N);
},
});
__END__
__C__
void do_inline(char * packed_data, int N_updates, int N_data) {
double * actual_data = (double *) packed_data;
int i;
for (i = 0; i < N_updates; i++) {
int index = rand() % N_data;
actual_data[index]++;
}
}
私にとって、Inline 関数は一貫して Perl と PDL の両方に勝っています。の大きな値$updates_per_round
、たとえば 1,000 の場合、Inline::C
のバージョンは、純粋な Perl よりも約 5 倍速く、PDL よりも 1.2 倍から 2 倍速くなります。が 1 の場合でも$updates_per_round
、Perl が PDL を簡単に打ち負かしますが、インライン コードは Perl コードよりも 2.5 倍高速です。
これだけを達成する必要がある場合は、 を使用することをお勧めしますInline::C
。
ただし、データに対して多くの操作を実行する必要がある場合は、そのパワー、柔軟性、およびパフォーマンスのために PDL を使用するのが最善です。vec()
PDL データの使用方法については、以下を参照してください。