Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在Python中计算点距离如此缓慢?_Python_Performance - Fatal编程技术网

为什么在Python中计算点距离如此缓慢?

为什么在Python中计算点距离如此缓慢?,python,performance,Python,Performance,我的Python程序太慢了。因此,我对它进行了分析,发现大部分时间都花在一个函数上,该函数计算两点之间的距离(一个点是由3个Python浮点组成的列表): 分析为什么这个函数这么慢,我写了两个测试程序:一个在Python中,一个在C++中进行类似的计算。他们计算100万对点之间的距离。(Python和C++中的测试代码如下) < Python计算需要2秒,而C++则需要0.02秒。相差100倍 为什么Python代码< St>>比C++代码慢得多?我如何 >加速> 以匹配C++的性能?< /P>

我的Python程序太慢了。因此,我对它进行了分析,发现大部分时间都花在一个函数上,该函数计算两点之间的距离(一个点是由3个Python浮点组成的列表):

分析为什么这个函数这么慢,我写了两个测试程序:一个在Python中,一个在C++中进行类似的计算。他们计算100万对点之间的距离。(Python和C++中的测试代码如下) < Python计算需要2秒,而C++则需要0.02秒。相差100倍

为什么Python代码< St>>比C++代码慢得多?我如何<强> >加速> <强>以匹配C++的性能?< /P> 用于测试的Python代码:

import math, random, time

num = 1000000

# Generate random points and numbers

pt_list = []
rand_list = []

for i in range(num):
    pt = []
    for j in range(3):
        pt.append(random.random())
    pt_list.append(pt)
    rand_list.append(random.randint(0, num - 1))

# Compute

beg_time = time.clock()
dist = 0

for i in range(num):
    pt0 = pt_list[i]
    ri  = rand_list[i]
    pt1 = pt_list[ri]

    val = 0
    for j in range(3):
        val += (pt0[j] - pt1[j]) ** 2
    val = math.sqrt(val)

    dist += val

end_time = time.clock()
elap_time = (end_time - beg_time)

print elap_time
print dist
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cmath>

struct Point
{
    double v[3];
};

int num = 1000000;

int main()
{
    // Allocate memory
    Point** pt_list = new Point*[num];
    int* rand_list = new int[num];

    // Generate random points and numbers
    for ( int i = 0; i < num; ++i )
    {
        Point* pt = new Point;

        for ( int j = 0; j < 3; ++j )
        {
            const double r = (double) rand() / (double) RAND_MAX;
            pt->v[j] = r;
        }

        pt_list[i] = pt;
        rand_list[i] = rand() % num;
    }

    // Compute

    clock_t beg_time = clock();
    double dist = 0;
    for ( int i = 0; i < num; ++i )
    {
        const Point* pt0 = pt_list[i];
        int r = rand_list[i];
        const Point* pt1 = pt_list[r];

        double val = 0;
        for ( int j = 0; j < 3; ++j )
        {
            const double d = pt0->v[j] - pt1->v[j];
            val += ( d * d );
        }

        val = sqrt(val);
        dist += val;
    }
    clock_t end_time = clock();
    double sec_time = (end_time - beg_time) / (double) CLOCKS_PER_SEC;

    std::cout << sec_time << std::endl;
    std::cout << dist << std::endl;

    return 0;
}

用于测试的C++代码:

import math, random, time

num = 1000000

# Generate random points and numbers

pt_list = []
rand_list = []

for i in range(num):
    pt = []
    for j in range(3):
        pt.append(random.random())
    pt_list.append(pt)
    rand_list.append(random.randint(0, num - 1))

# Compute

beg_time = time.clock()
dist = 0

for i in range(num):
    pt0 = pt_list[i]
    ri  = rand_list[i]
    pt1 = pt_list[ri]

    val = 0
    for j in range(3):
        val += (pt0[j] - pt1[j]) ** 2
    val = math.sqrt(val)

    dist += val

end_time = time.clock()
elap_time = (end_time - beg_time)

print elap_time
print dist
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cmath>

struct Point
{
    double v[3];
};

int num = 1000000;

int main()
{
    // Allocate memory
    Point** pt_list = new Point*[num];
    int* rand_list = new int[num];

    // Generate random points and numbers
    for ( int i = 0; i < num; ++i )
    {
        Point* pt = new Point;

        for ( int j = 0; j < 3; ++j )
        {
            const double r = (double) rand() / (double) RAND_MAX;
            pt->v[j] = r;
        }

        pt_list[i] = pt;
        rand_list[i] = rand() % num;
    }

    // Compute

    clock_t beg_time = clock();
    double dist = 0;
    for ( int i = 0; i < num; ++i )
    {
        const Point* pt0 = pt_list[i];
        int r = rand_list[i];
        const Point* pt1 = pt_list[r];

        double val = 0;
        for ( int j = 0; j < 3; ++j )
        {
            const double d = pt0->v[j] - pt1->v[j];
            val += ( d * d );
        }

        val = sqrt(val);
        dist += val;
    }
    clock_t end_time = clock();
    double sec_time = (end_time - beg_time) / (double) CLOCKS_PER_SEC;

    std::cout << sec_time << std::endl;
    std::cout << dist << std::endl;

    return 0;
}
#包括
#包括
#包括
#包括
结构点
{
双v[3];
};
int num=1000000;
int main()
{
//分配内存
点**点列表=新点*[num];
int*rand_list=新int[num];
//生成随机点和随机数
对于(int i=0;iv[j]=r;
}
pt_list[i]=pt;
rand_list[i]=rand()%num;
}
//计算
时钟时间=时钟();
双距离=0;
对于(int i=0;iv[j]-pt1->v[j];
val+=(d*d);
}
val=sqrt(val);
dist+=val;
}
时钟结束时间=时钟();
双秒时间=(结束时间-乞讨时间)/(双)时钟/秒;
std::cout一些一般提示:

将所有代码移到main()函数中,并使用普通

if __name__ == "__main__":
    main()
构造。由于范围可变,它大大提高了速度。 有关原因的解释,请参阅


不要使用<代码> Range[A]或代码>,因为它一次生成完整的范围,对于大数来说是慢的;而使用<代码> xRange[](/Cuff>),它使用生成器。

不能期望在Python中匹配C++的性能,但是可以稍微修改Python代码以使它更快:

def get_dist(pt0, pt1):
    val = 0
    for i in range(3):
        val += (pt0[i] - pt1[i]) ** 2
    val = math.sqrt(val)
    return val
<>代码> <代码>循环版本,C++代码< > 循环完全不同。Python版本创建一个列表,然后迭代它,而C++版本只是增加变量。如果你想加快Python版本,最好的方法是显式地写出来,以节省开销。Python
用于循环

def get_dist(pt0, pt1, sqrt=math.sqrt): # cache function at definition time
    return sqrt((pt0[0] - pt1[0]) ** 2 + (pt0[1] - pt1[1]) ** 2 + (pt0[2] - pt1[2]) ** 2)

这可能是你能得到的最快速度(不使用
numpy
),对于这个特定的函数,你还可以在主代码中改进其他东西。

Python不是一种快速语言,它不生成“计算机代码”,它在Python虚拟机中运行。“一切”是对象,所以您没有C中的静态类型。只有这样才能大大降低速度。 -无论如何,那不是我的领域,所以我不会谈论太多

你应该考虑PyPy、Cython,甚至可以在C.

中编写Python扩展。
我用PyPy运行代码,使用的时间是250ms这个页面变得非常混乱,大多数答案实际上都在注释中,下面是可能的优化的快速概述:

  • :优化python代码:

    def get_dist(pt0, pt1, sqrt=math.sqrt):  # cache function at definition time
        return sqrt((pt0[0] - pt1[0]) ** 2 + (pt0[1] - pt1[1]) ** 2 + (pt0[2] - pt1[2]) ** 2) 
    
  • 使用numpy模块进行计算

  • 用pypy而不是CPython运行代码
  • 将时间关键代码与Cython进行比较

    • 一系列优化:

      原始代码,稍加修改

      优化#1:将代码放入函数中。 第一个优化(未显示)是将除导入
之外的所有代码嵌入到函数中。这个简单的更改为我的计算机提供了36%的性能提升


优化#2:避免使用
**
操作符。 您不使用
pow(d,2)
在您的C代码中,因为每个人都知道这在C代码中是次优的。在python中也是次优的。python的
**
是智能的;它将
x**2
计算为
x*x
。但是,智能化需要时间。您知道您想要
d*d
,所以使用它。下面是该优化的计算循环:

for i in range(num):
    pt0 = pt_list[i]
    ri  = rand_list[i]
    pt1 = pt_list[ri]

    val = 0 
    for j in range(3):
        d = pt0[j] - pt1[j]
        val += d*d 
    val = math.sqrt(val)

    dist += val 

优化#3:像蟒蛇一样。 你的Python代码看起来很像你的C代码。你没有利用这种语言

import math, random, time, itertools

def main (num=1000000) :
    # This small optimization speeds things up by a couple percent.
    sqrt = math.sqrt

    # Generate random points and numbers

    random.seed (0x7126434a2ea2a259e9f4196cbb343b1e6d4c2fc8)

    def random_point () :
        return [random.random(), random.random(), random.random()]

    def random_index () :
       return random.randint(0, num-1)

    # Big optimization:
    # Don't generate the lists of points.
    # Instead use list comprehensions that create iterators.
    # It's best to avoid creating lists of millions of entities when you don't
    # need those lists. You don't need the lists; you just need the iterators.
    pt_list = [random_point() for i in xrange(num)]
    rand_pts = [pt_list[random_index()] for i in xrange(num)]


    # Compute

    beg_time = time.clock()
    dist = 0 

    # Don't loop over a range. That's too C-like.
    # Instead loop over some iterable, preferably one that doesn't create the
    # collection over which the iteration is to occur.
    # This is particularly important when the collection is large.
    for (pt0, pt1) in itertools.izip (pt_list, rand_pts) :

        # Small optimization: inner loop inlined,
        # intermediate variable 'val' eliminated.
        d0 = pt0[0]-pt1[0]
        d1 = pt0[1]-pt1[1]
        d2 = pt0[2]-pt1[2]

        dist += sqrt(d0*d0 + d1*d1 + d2*d2)

    end_time = time.clock()
    elap_time = (end_time - beg_time)

    print elap_time
    print dist

更新 优化#4,使用numpy 在代码的计时部分,下面的代码大约花费了原始版本时间的1/40。速度不如C,但接近

请注意注释掉的“Mondo slow”计算。这大约是原始版本的十倍。使用numpy会带来开销。与我的非numpy优化#3相比,下面的代码中的设置花费的时间要长得多

一句话:使用numpy时需要小心,安装成本可能会很高

import numpy, random, time

def main (num=1000000) :

    # Generate random points and numbers

    random.seed (0x7126434a2ea2a259e9f4196cbb343b1e6d4c2fc8)

    def random_point () :
        return [random.random(), random.random(), random.random()]

    def random_index () :
       return random.randint(0, num-1)

    pt_list = numpy.array([random_point() for i in xrange(num)])
    rand_pts = pt_list[[random_index() for i in xrange(num)],:]

    # Compute

    beg_time = time.clock()

    # Mondo slow.
    # dist = numpy.sum (
    #            numpy.apply_along_axis (
    #                numpy.linalg.norm, 1, pt_list - rand_pts))

    # Mondo fast.
    dist = numpy.sum ((numpy.sum ((pt_list-rand_pts)**2, axis=1))**0.5)

    end_time = time.clock()
    elap_time = (end_time - beg_time)

    print elap_time
    print dist

因为编译后的代码总是会击败字节码解释的动态语言?使用
numpy
在如此大的数据集上进行计算。这不是对你问题的回答,但是,你考虑过使用numpy吗?@Ashwin:你在这里没有充分利用Python的优势,你的代码也不是最有效的。使用local scope vs.global作用域会有所不同,展开循环和避免属性取消引用也会有所帮助。您也可以尝试使用pypy运行此代码。编辑:对我来说,pypy比CPython快6.5倍。在比较C和CPython时,我预计“简单数学计算”会有100倍的差异。如果一个模块生成数百万个3D点