【问题标题】:Performant math operations on large Perl6 CArrays?大型 Perl6 CArray 上的高性能数学运算?
【发布时间】:2018-12-22 08:17:35
【问题描述】:

我有一些由本机子返回的大型 CArray,我需要对其执行基本的逐元素数学运算。 CArray 通常是 10^6 个元素的数量级。我发现在它们上调用 .list 以将它们视为普通的 Perl6 类型非常昂贵。有没有办法在保持 CArrays 的同时对它们进行高性能的元素操作?

简短的测试脚本来计时我尝试过的一些方法:

#!/usr/bin/env perl6
use v6.c;
use NativeCall;
use Terminal::Spinners;

my $list;
my $carray;
my $spinner = Spinner.new;

########## create data stuctures ##########

print "Creating 10e6 element List and CArray  ";
my $create = Promise.start: {
    $list = 42e0 xx 10e6;
    $carray = CArray[num32].new($list);
}
$spinner.await: $create;

########## time List subtractions ##########

my $time = now;
print "Substracting two 10e6 element Lists w/ hyper  ";
$spinner.await( Promise.start: {$list >>-<< $list} );
say "List hyper subtraction took: {now - $time} seconds";

$time = now;
print "Substracting two 10e6 element Lists w/ for loop  ";
my $diff = Promise.start: {
    for ^$list.elems {
        $list[$_] - $list[$_];
    }
}
$spinner.await: $diff;
say "List for loop subtraction took: {now - $time} seconds";

########## time CArray subtractions ##########

$time = now;
print "Substracting two 10e6 element CArrays w/ .list and hyper  ";
$spinner.await( Promise.start: {$carray.list >>-<< $carray.list} );
say "CArray .list and hyper subtraction took: {now - $time} seconds";

$time = now;
print "Substracting two 10e6 element CArrays w/ for loop  ";
$diff = Promise.start: {
    for ^$carray.elems {
        $carray[$_] - $carray[$_];
    }
}
$spinner.await: $diff;
say "CArray for loop subtraction took: {now - $time} seconds";

输出:

Creating 10e6 element List and CArray |
Substracting two 10e6 element Lists w/ hyper -
List hyper subtraction took: 26.1877042 seconds
Substracting two 10e6 element Lists w/ for loop -
List for loop subtraction took: 20.6394032 seconds
Substracting two 10e6 element CArrays w/ .list and hyper /
CArray .list and hyper subtraction took: 164.4888844 seconds
Substracting two 10e6 element CArrays w/ for loop |
CArray for loop subtraction took: 133.00560218 seconds

for 循环方法似乎最快,但 CArray 的处理时间仍然是 List 的 6 倍。

有什么想法吗?

【问题讨论】:

  • 使 .list 方法比它需要的慢得多的一个因素是,它首先为 CArray 中的每个插槽创建两个列表,其中包含一个标量 + 一个 Int(或者可能是一个 NativeRef),这导致大量分配和内存使用
  • 我刚刚向 rakudo 推送了一个提交,这使得 CArray 上的 $foo[ ] 花费不到 ½ 时间。

标签: raku nativecall


【解决方案1】:

只要您可以使用不同的本机数据类型矩阵和向量,您就可以使用Gnu Scientific Library by Fernando Santagata 的(也是本机)端口。它有一个可以使用的 Vector.sub 函数。

#!/usr/bin/env perl6
use v6.c;
use NativeCall;
use Terminal::Spinners;
use Math::Libgsl::Vector;

my $list;
my $carray;
my $spinner = Spinner.new;

########## create data stuctures ##########

print "Creating 10e6 element List and CArray  ";
my $list1 = Math::Libgsl::Vector.new(size => 10e6.Int);
$list1.setall(42);
my $list2 = Math::Libgsl::Vector.new(size => 10e6.Int);
$list2.setall(33);

########## time List subtractions ##########

my $time = now;
print "Substracting two 10e6 element Lists w/ hyper  ";
$spinner.await( Promise.start: { $list1.sub( $list2)} );
say "GSL Vector subtraction took: {now - $time} seconds";

这需要:

GSL Vector subtraction took: 0.08243 seconds

这对你来说够快吗? :-)

【讨论】:

  • 这看起来是一个相当不错的高性能模块。我早就通过使用 C++ 或 Rust 解决这些类型的问题来解决这个问题,但是很高兴看到 Raku 得到这样的模块。
  • 感谢 Frithnath,他煞费苦心地为整个库创建包装器。
猜你喜欢
  • 2011-03-08
  • 2013-10-05
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多