你想要的PDL命令是indadd
。 (感謝PDK Pumpking的Chris Marshall爲我指出這一點elsewhere。)
PDL是爲我所謂的「矢量化」操作而設計的。與C操作相比,Perl操作非常緩慢,因此您希望將PDL方法調用的數量降至最低,並且每次調用都要做很多工作。例如,此基準測試可讓您指定一次執行的更新數(作爲命令行參數)。 Perl的側面有環,但PDL側僅執行五年左右的函數調用:
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% --
而且每回合萬次更新,PDL優於Perl的由四個因素:
$ perl script.pl 10000
Rate perl pdl
perl 221/s -- -75%
pdl 881/s 298% --
PDL繼續執行大約快4倍比普通的Perl更大的值。
請注意,對於更復雜的操作,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]++;
}
}
對於我來說,內聯函數始終跳動都Perl和PDL。對於$updates_per_round
的較大值,比如說1,000,我得到的Inline::C
的版本大約比純Perl快5倍,比PDL快1.2倍和2倍。即使$updates_per_round
僅僅是1,Perl在Perl中輕鬆跳過PDL,Inline代碼比Perl代碼快2.5倍。
如果這是全部您需要完成,我推薦使用Inline::C
。但是,如果您需要對數據執行很多操作,則最好堅持使用PDL的強大功能,靈活性和性能。請參閱下文,瞭解如何將vec()
與PDL數據一起使用。
有你看着生物信息學perl模塊? – AlfredoVR 2012-03-16 01:46:11