Python xtensor';s";操作员/";比numpy慢';s"/&引用;

Python xtensor';s";操作员/";比numpy慢';s"/&引用;,python,c++,numpy,xtensor,Python,C++,Numpy,Xtensor,我试图把以前用python编写的代码转换成C++,我现在正在测试xTrxor,看看它是否比NuPy更快,以满足我需要的。 我的一个函数接受一个方阵d和一个标量alpha,并执行元素操作alpha/(alpha+d)。背景:此函数用于测试alpha的哪个值为“最佳”,因此它处于一个循环中,d始终相同,但alpha不同 以下所有时间尺度平均为运行函数的100个实例 在numpy中,执行此操作大约需要0.27秒,代码如下: def kfun(d,alpha): k = alpha /(d+al

我试图把以前用python编写的代码转换成C++,我现在正在测试xTrxor,看看它是否比NuPy更快,以满足我需要的。 我的一个函数接受一个方阵d和一个标量alpha,并执行元素操作
alpha/(alpha+d)
。背景:此函数用于测试
alpha
的哪个值为“最佳”,因此它处于一个循环中,
d
始终相同,但
alpha
不同

以下所有时间尺度平均为运行函数的100个实例

在numpy中,执行此操作大约需要0.27秒,代码如下:

def kfun(d,alpha):
    k = alpha /(d+alpha)
    return k
但是xtensor大约需要0.36秒,代码如下所示:

xt::xtensor<double,2> xk(xt::xtensor<double,2> d, double alpha){
    return alpha/(alpha+d);
}
我注意到xtensor中的
操作符/
使用了“惰性广播”,是否有办法使其立即生效

编辑:

在Python中,函数调用如下,并使用“time”包计时

<>在C++中,调用函数如下,使用的是计时:

//d is saved as a 1D npy file, an artefact from old code
auto sd2 = xt::load_npy<double>("/path/to/d.npy");

shape = {7084, 7084};
    xt::xtensor<double, 2> xd2(shape);
    for (int i = 0; i<7084;i++){
        for (int j=0; j<7084;j++){
            xd2(i,j) = (sd2(i*7084+j));
        }
    }

auto start = std::chrono::steady_clock::now();
for (int i = 0;i<10;i++){
    matrix<double> kk = kfun(xd2,4000*4000,7084);
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "k takes: " << elapsed_seconds.count() << "\n";


提前谢谢

> P>一个C++实现的问题可能是它创建了一个或者可能是两个临时副本,这是可以避免的。第一个副本来自未通过引用传递参数(或完全转发)。如果不看代码的其余部分,就很难判断这是否对性能有影响。如果保证在方法
xk()
之后不使用该方法,编译器可以将
d
移动到该方法中,但更可能将数据复制到
d

要通过引用传递,可以将方法更改为

xt::xtensor xk(常数xt::xtensor&d,双alpha){
返回alpha/(alpha+d);
}
要使用完美转发(并启用其他xtensor容器,如
xt::xarray
xt::xtensor\u fixed
),可以将该方法更改为

模板
xt::xtensor xk(T&d,双阿尔法){
返回alpha/(alpha+d);
}
此外,您可以避免为返回值保留内存。同样,如果没有看到代码的其余部分,就很难做出判断。但是,如果在循环内部使用该方法,并且返回值始终具有相同的形状,那么在循环外部创建返回值并通过引用返回是有益的。为此,可将方法更改为:

模板
void xk(T&r、U&d、双阿尔法){
r=α/(α+d);
}
如果保证
d
r
不指向同一内存,则可以在
xt::noalias()
中进一步包装
r
,以避免在分配结果之前进行临时复制。如果不通过引用返回,函数的返回值也是如此


祝你好运和快乐

好问题!改进该问题的一个一般性意见是,一个最小的可复制示例会更好。具体来说,您可以包括用于调用函数的几行代码。这将使人们更容易判断有关副本的微妙之处。更详细的一点是,您的
std::vector
示例似乎没有分配返回值。此外,一般来说,您应该使用
来(int i=0;i@TomdeGeus您好!谢谢您的评论。我只是想澄清一下,显然我对这一点很陌生,但我想如果我只是指定了大小,而不是每次都让它计算出来,那么这个函数会更快?这是错误的吗?这个函数是在循环中调用的,特别是使用不同的alpha.a值lso,你说我的std::vector示例不分配返回值是什么意思?我知道你可以为一个对输入进行更改的示例执行一个void函数,例如,我是否意外地这样做了,而不是输出一个修改过的“d”?编译器可能会优化(部分)size调用,但老实说,您的
d_size
选项从我的屏幕上掉了出来,因此我没有注意到is,并假设您可能有一个输入错误。对于vector示例,您有一些未定义的
d2
,但您更正了此错误,所以一切都很好!关于这个问题的一个小评论。通过最新的编辑,这个问题得到了很多b更好的方法是确保代码片段的可复制性:任何人都可以复制您的代码片段,并直接编译和运行它。为此,您可以简单地将
dsquared
xd2
作为一个随机矩阵引入numbers@TomdeGeus你介意吗,我在编辑栏底部写的内容可以吗?还是我应该上传一个例子?嗨!谢谢你的回答!我只是想澄清一下,因为我不认为我在我的问题中指定了,我需要保留原始的d矩阵,还需要输出一个名为“k”的矩阵,这是因为我基本上需要尝试大量不同的alpha值,看看哪个值“最好”结果。我相信你的建议不允许这样做,这是正确的吗?抱歉,这是我的第一个堆栈溢出问题,我想我没有给出足够的信息。在我看来,在C++方面这个问题很重要,就是:abab011发现向量示例是比较快的,而原则上包含相同的副本。你在这个答案中提到了。所以,消除副本可以解释NumPy与NumPy的区别,而NumPy实际上也不会复制副本(如果@abic011可以确认,那就太好了,但不能使用
std::vector
版本。如果拷贝数相同,两个版本在最坏情况下应该是相同的快/慢@abic001,为了回答关于保持矩阵
d
不变的问题,这没有问题。您仍然可以将
d
作为常量引用传递(我的第一个建议)方法调用会快得多。函数不会更改矩阵
d
。关于矩阵
k
,请编辑您的问题以显示其用法?抱歉!复制时
t0 = time.time()
for i in range(100):
    kk = k(dsquared,alpha_squared)
print(time.time()-t0)
//d is saved as a 1D npy file, an artefact from old code
auto sd2 = xt::load_npy<double>("/path/to/d.npy");

shape = {7084, 7084};
    xt::xtensor<double, 2> xd2(shape);
    for (int i = 0; i<7084;i++){
        for (int j=0; j<7084;j++){
            xd2(i,j) = (sd2(i*7084+j));
        }
    }

auto start = std::chrono::steady_clock::now();
for (int i = 0;i<10;i++){
    matrix<double> kk = kfun(xd2,4000*4000,7084);
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "k takes: " << elapsed_seconds.count() << "\n";

cd "/path/to/src/" && g++ -mavx2 -ffast-math -DXTENSOR_USE_XSIMD -O3 ccode.cpp -o ccode -I/path/to/xtensorinclude && "/path/to/src/"ccode