Lệnh PDL bạn muốn là indadd
. (Cảm ơn Chris Marshall, PDL Pumpking, vì đã chỉ ra điều đó cho tôi elsewhere.)
PDL được thiết kế cho những gì tôi gọi là các hoạt động "được vectơ hóa". So với các phép toán C, các hoạt động của Perl khá chậm, vì vậy bạn muốn giữ số lượng các lời gọi phương thức PDL ở mức tối thiểu, và có mỗi lời gọi thực hiện rất nhiều công việc. Ví dụ, điểm chuẩn này cho phép bạn chỉ định số lượng các bản cập nhật để thực hiện trong một lần đi (như một tham số dòng lệnh). Phía perl có để lặp, nhưng phía PDL chỉ thực hiện năm hoặc để gọi hàm:
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);
}
});
Khi tôi chạy này với một cuộc tranh cãi trong tổng số 1, tôi nhận được hiệu suất thậm chí còn tồi tệ hơn khi sử dụng set
, đó là những gì tôi dự kiến:
$ perl script.pl 1
Rate pdl perl
pdl 21354/s -- -98%
perl 1061925/s 4873% --
Đó là rất nhiều điểm để tạo nên! Nhưng giữ trong đó. Nếu chúng ta làm 100 lần lặp mỗi vòng, chúng tôi nhận một sự cải tiến:
$ perl script.pl 100
Rate pdl perl
pdl 16906/s -- -18%
perl 20577/s 22% --
Và với 10.000 cập nhật mỗi vòng, PDL nhanh hơn so với Perl bởi một yếu tố của bốn:
$ perl script.pl 10000
Rate perl pdl
perl 221/s -- -75%
pdl 881/s 298% --
PDL tiếp tục thực hiện nhanh hơn khoảng 4x hơn Perl đơn giản cho các giá trị lớn hơn.
Lưu ý rằng hiệu suất của PDL có thể làm suy giảm cho các hoạt động phức tạp hơn. Điều này là do PDL sẽ phân bổ và phá bỏ các vùng làm việc lớn nhưng tạm thời cho các hoạt động trung gian. Trong trường hợp đó, bạn có thể cân nhắc sử dụng Inline::Pdlpp
. Tuy nhiên, đó không phải là công cụ của người mới bắt đầu, vì vậy đừng nhảy đến đó cho đến khi bạn đã xác định nó thực sự là điều tốt nhất cho bạn.
Một thay thế cho tất cả điều này là sử dụng Inline::C
như vậy:
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]++;
}
}
Đối với tôi, hàm Inline liên tục đánh bại cả hai Perl và PDL. Đối với các giá trị lớn của $updates_per_round
, nói 1.000, tôi nhận được Inline::C
của phiên bản khoảng 5x nhanh hơn so với Perl tinh khiết và giữa 1.2x và 2x nhanh hơn so với PDL. Ngay cả khi $updates_per_round
chỉ là 1, trong đó Perl đánh bại PDL một cách thủ công, mã Inline nhanh hơn 2.5 lần so với mã Perl.
Nếu đây là tất cả bạn cần thực hiện, tôi khuyên bạn nên sử dụng Inline::C
.
Nhưng nếu bạn cần thực hiện nhiều thao tác với dữ liệu của mình, bạn nên gắn bó với PDL về sức mạnh, tính linh hoạt và hiệu suất của nó. Xem bên dưới để biết cách bạn có thể sử dụng vec()
với dữ liệu PDL.
có bạn nhìn các mô-đun perin tin sinh học? – AlfredoVR