python在for循环方面的效率是难以置信的低,还是仅仅是我的代码?
我的问题不是关于我的代码,而是关于python的。我们家有一场编码竞赛,我父母分别用C#和javascript编写了这个项目的版本。我认为python应该和其他语言一样高效,如果不是比其他语言更高效的话。我们最终编写了相同的代码(显然语法不同),但它们的文件在几毫秒内运行(我爸爸用Javascript写221个,我妈妈用C#写500个),我的文件在大约5分钟内运行。这是一个荒谬的区别,让我质疑python究竟是如何应用于现实世界的数据处理和算法求解的python在for循环方面的效率是难以置信的低,还是仅仅是我的代码?,python,python-3.x,algorithm,pythagorean,Python,Python 3.x,Algorithm,Pythagorean,我的问题不是关于我的代码,而是关于python的。我们家有一场编码竞赛,我父母分别用C#和javascript编写了这个项目的版本。我认为python应该和其他语言一样高效,如果不是比其他语言更高效的话。我们最终编写了相同的代码(显然语法不同),但它们的文件在几毫秒内运行(我爸爸用Javascript写221个,我妈妈用C#写500个),我的文件在大约5分钟内运行。这是一个荒谬的区别,让我质疑python究竟是如何应用于现实世界的数据处理和算法求解的 我用毕达哥拉斯数三元组解决了一个问题。问题
我用毕达哥拉斯数三元组解决了一个问题。问题是,如果a的平方+b的平方=c的平方,那么只有a,b和c的一个组合加起来就是一千。最后,打印制作1000所需的数字,分次打印在一起
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
print("I have found it")
print(a*b*c)
quit()
与静态类型语言相比,Python通常效率较低。除了动态类型化之外,Python在其他几个方面都是动态的,比如某些操作的长链回退,
用于任何iterable上的循环,,上下文管理器,等等,这些都可以用于非常广泛的对象集。这些特性使编程变得方便,但通常会带来一定的成本。因此,优化的Python程序将经常被C++、Haskell、java等程序中的一个等效程序优于
但是我认为主要的问题是你的算法不是很有效。这里有三个循环,每个循环的范围超过999项。这意味着内部循环最多执行997'002'999次。我们可以重写算法,使其最多需要499'500次迭代,如下所示:
for c in range(1000, 0, -1):
for a in range(999-c, 0, -1):
b = 1000-a-c
if a*a + b*b == c*c:
print("I have found it")
print(a*b*c)
quit()
因此,这将在27.6毫秒内运行。通过使用毕达哥拉斯三元组的平方和关系,您可以进一步加快该过程。在这个实现中可以看到
我自己用下面的代码进行了测试,发现它可以在十分之二毫秒内运行
import math
import time
def pythagoreanTriplets(limits) :
c, m = 0, 2
# Limiting c would limit
# all a, b and c
while c < limits :
# Now loop on n from 1 to m-1
for n in range(1, m) :
a = m * m - n * n
b = 2 * m * n
c = m * m + n * n
# if c is greater than
# limit then break it
if limits%(a+b+c) ==0:
#print(1000/(a+b+c)*a,1000/(a+b+c)*b,1000/(a+b+c)*c, "Found")
return
print(a, b, c)
m = m + 1
start = time.process_time()
pythagoreanTriplets(1000)
elapsed = time.process_time()
elapsed = elapsed - start
print("Time spent in (function name) is: ", elapsed)
导入数学
导入时间
def毕达哥拉斯三联体(限值):
c、 m=0,2
#限制c将限制
#全部a、b和c
而c<限制:
#现在在n上从1循环到m-1
对于范围(1,m)内的n:
a=m*m-n*n
b=2*m*n
c=m*m+n*n
#如果c大于
#限制然后打破它
如果限值%(a+b+c)==0:
#打印(1000/(a+b+c)*a,1000/(a+b+c)*b,1000/(a+b+c)*c,“已找到”)
回来
印刷品(a、b、c)
m=m+1
开始=时间。处理时间()
毕达哥拉斯三胞胎(1000)
已用时间=时间。处理时间()
已用=已用-开始
打印(“在(函数名)中花费的时间:”,已用)
正如威廉所说,高效的代码是这里最大的因素。
用Pete的见解更新了上述代码
我用print语句运行了一次代码以确保它的正确性,一次没有看到速度,它显示了大约20倍的下降
我们可以使Python for循环更快
发帖人的问题是为什么Python“for循环”相对于C#和JavaScript速度如此之慢。提出一种不同的算法来减少对“for循环”的需求并不能解决这一问题(特别是因为C#和JavaScript版本使用修改后的算法也会更快)。在一般情况下,编程语言是使用类似的算法进行比较的,它们的区别是由允许它们在一项任务中表现出色的语言特性实现的--
在本例中,任务是使用Python语言功能更快地搜索超过10亿个数字(三个嵌套for循环的大小)
尝试了两种方法来加速代码:Cython和Numba(分别)
设置:
- Jupyter笔记本
- Python 3.5.2操作系统
- Windows 10 64位
- 处理器i7
结果:
Python 3.5.2=>387.356秒
Cython=>117.223秒
Cython(改进)=>0.63秒(使用@codesculator建议)
Numba=>0.5秒
Numba版本可与海报的JavaScript和C#times相媲美。
使用相同的“次优”算法,Numba在纯Python上提供了774的速度提升。请注意,这三个实现使用的代码基本相同,如下所示
Python 3.5.2代码
Python 3.5.2输出
I have found it 31875000
Elapsed Time
387.3550021648407
Cython代码(请参阅)
Cython输出
I have found it 31875000
('Elapsed Time\n', 117.22299981117249)
Cython(带Cdef)
%%cython-a
导入时间
cdef int solve():
cdef int a、b、c
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
return a*b*c
t0=时间。时间()
打印('我找到它{}'。格式(solve())
打印(“已用时间\n”,Time.Time()-t0)
输出(使用Cdef的Cython)
Numba代码(请参阅)
麻木产量
I have found it 31875000
Elapsed Time
0.5209996700286865
似乎有很多重复的计算可以从循环中取出,所以我决定预先计算平方。
sqrs
作为dict执行三项任务:
它只需迭代sqrs.items()
,就可以循环x和x**2
它允许查找**2+b**2本身是否为正方形
如果上一个任务为true,则允许查找c
以下是计时代码:
def original():
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
print("I have found it")
print(a*b*c)
return
%time original()
I have found it
31875000
Wall time: 2min 27s
def pre_compute_sqrs():
sqrs = {x**2:x for x in range(1, 1001)}
for aa, a in sqrs.items():
for bb, b in sqrs.items():
ab, aabb = a + b, aa + bb
if ab >= 1000 or aabb >= 1_000_000:
break
if aabb not in sqrs:
continue
c = sqrs[aabb]
if a+b+c == 1000:
print("I have found it")
print(a*b*c)
return
%time pre_compute_sqrs()
I have found it
31875000
Wall time: 46.9 ms
Python速度慢吗?可能是
通常是不是太慢了?不,通常不会。以上内容将总共运行10亿次迭代。以上不是找到解决方案的有效方法。你爸爸用另一种方法解决了这个问题。。。但是你的问题的答案是Python很慢。。。但并不是说你在毫无必要地重新计算a^2和c^2。当每个人问我的父母是否使用了相同的算法时,他们确实这么做了。但python的速度仍然慢得惊人!感谢到目前为止的所有答案:)要在python中进行数据处理,您(1)使用更智能的算法(您在这里进行了大量冗余计算)和(2)d
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
return a*b*c
I have found it 31875000
('Elapsed Time\n', 0.6340005397796631)
import time
from numba import jit
@jit(nopython=True) # only need to add Numba decorator to get speed up
def solve():
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
return a*b*c
t0 = time.time()
print('I have found it {}'.format(solve()))
print("Elapsed Time\n", time.time()- t0)
I have found it 31875000
Elapsed Time
0.5209996700286865
def original():
for c in range(1000, 0, -1):
for a in range(1000, 0, -1):
for b in range(1000, 0, -1):
if (a*a)+(b*b)==(c*c):
if a+b+c == 1000:
print("I have found it")
print(a*b*c)
return
%time original()
I have found it
31875000
Wall time: 2min 27s
def pre_compute_sqrs():
sqrs = {x**2:x for x in range(1, 1001)}
for aa, a in sqrs.items():
for bb, b in sqrs.items():
ab, aabb = a + b, aa + bb
if ab >= 1000 or aabb >= 1_000_000:
break
if aabb not in sqrs:
continue
c = sqrs[aabb]
if a+b+c == 1000:
print("I have found it")
print(a*b*c)
return
%time pre_compute_sqrs()
I have found it
31875000
Wall time: 46.9 ms