这是两个程序,它们天真地计算素数的数量< = n
一个是Python,另一个是Java。
public class prime{
public static void main(String args[]){
int n = Integer.parseInt(args[0]);
int nps = 0;
boolean isp;
for(int i = 1; i <= n; i++){
isp = true;
for(int k = 2; k < i; k++){
if( (i*1.0 / k) == (i/k) ) isp = false;
}
if(isp){nps++;}
}
System.out.println(nps);
}
}
`#!/usr/bin/python`
import sys
n = int(sys.argv[1])
nps = 0
for i in range(1,n+1):
isp = True
for k in range(2,i):
if( (i*1.0 / k) == (i/k) ): isp = False
if isp == True: nps = nps + 1
print nps
在n = 10000上运行它我得到以下时间
shell:〜$ time python prime.py 10000&amp;&amp;时间java prime 10000
1230
真实0m49.833s
用户0m49.815s
sys 0m0.012s
1230
真实0m1.491s
用户0m1.468s
sys 0m0.016s
我是否在python中以不正确的方式使用for循环,或者python实际上只是这么慢?
我不是在寻找专门用于计算素数的答案,而是我想知道python代码是否通常以更智能的方式使用。
编译Java代码
javac 1.6.0_20
使用java版本“1.6.0_18”运行
OpenJDK运行时环境(IcedTea6 1.8.1)(6b18-1.8.1-0ubuntu1~9.10.1)
OpenJDK客户端VM(构建16.0-b13,混合模式,共享)
Python是:
Python 2.6.4(r264:75706,2009年12月7日,18:45:15)
答案 0 :(得分:9)
正如已经指出的那样,直接Python真的不是为了这种事情。主要检查算法是天真的也不是重点。但是,通过两个简单的操作,我可以在使用原始算法时大大缩短Python的时间。
首先,将所有内容放在函数中,将其称为main()
或其他内容。这使我的机器在Python上的时间从20.6秒减少到14.54秒。全局做事比在函数中做事要慢。
其次,使用JIT编译器Psyco。这需要在文件顶部添加两行(当然还安装了psyco):
import psyco
psyco.full()
这使最终时间达到2.77秒。
最后一点。我决定在此使用Cython并将时间降至0.8533。但是,知道如何进行少量更改以使其快速运行Cython代码不是我为临时用户推荐的内容。
答案 1 :(得分:4)
是的,Python速度慢,比C慢一百倍。你可以使用xrange
代替范围来获得一个小的加速,但除此之外它没关系。
最终你做错的是你用普通的Python做到这一点,而不是使用像Numpy或Psyco这样的优化库。
Java附带了一个jit编译器,它可以在您处理数字时产生很大的不同。
答案 2 :(得分:2)
使用
替换复杂的测试,可以使Python的速度提高一倍if i % k == 0: isp = False
你也可以比isp = False后加入一个中断快8倍(n = 10000)。
另外,请帮个忙,跳过偶数(加1到nps开始包括2)。
最后,你只需要k到达sqrt(i)。
当然,如果你在Java中进行相同的更改,它仍然比优化的Python快10倍。
答案 3 :(得分:2)
男孩,当你说这是一个天真的实施时,你肯定不是在开玩笑!
但是,在将JIT编译的优化机器代码与解释语言进行比较时,性能上的一到两个数量级的差异并不出乎意料。在Java VM上运行的替代Python实现(如Jython)可能会更快地执行此任务;你可以给它一个旋转。 Cython,允许您向Python添加静态类型并在某些情况下获得类似C的性能,也可能值得研究。
即使在考虑标准的Python解释器CPython时,问题是:Python是否足够快以完成手头的任务?您是否节省了使用Python等动态语言编写代码的时间,以弥补运行它所花费的额外时间?如果你不得不用Java编写一个给定的程序,那么看起来太值得做的事情值得吗?
例如,考虑在现代计算机上运行的Python程序与在10年前的计算机上运行的Java程序一样快。你十年前的计算机很快就可以用很多东西了,不是吗?
Python确实具有许多功能,使其非常适合数字工作。这些包括支持无限数量的数字的整数类型,具有无限精度的十进制类型,以及专门用于计算的名为NumPy的可选库。然而,执行速度通常不是其声名鹊起的主要原因之一。它擅长的地方在于让计算机以最小的认知摩擦做你想做的事。
答案 4 :(得分:0)
如果您希望快速完成,Python可能不是前进的方法,但您可以加快速度。首先,你使用相当慢的方法来测试可分性。 Modulo更快。您也可以在检测到匹配后立即停止内循环(使用k)。我会做这样的事情:
nps = 0
for i in range(1, n+1):
if all(i % k for k in range(2, i)): # i.e. if divisible by none of them
nps += 1
对我来说,从25秒降到1.5秒。使用xrange将其降低到0.9秒。
你可以通过保留你已经找到的素数列表来进一步加速它,并且只测试那些,而不是每个数字直到i(如果我不能被2整除,它将不能被它整除4,6,8 ......)。
答案 5 :(得分:0)
为什么不发布有关内存使用情况的内容 - 而不仅仅是速度?试图在tomcat上获得一个简单的servlet在我的服务器上浪费了3GB。
你对这些例子做了什么并不是很好。你需要使用numpy。用while循环替换/ range,从而避免创建列表。
最后,python非常适合数字运算,至少是那些以正确方式运行的人,并且知道Eratosthenes的Sieve是什么,或者mod操作是什么。
答案 6 :(得分:0)
你可以对这个算法做很多事情来加速它,但是大多数它们也会加速Java版本。其中一些将比Java更加加速Python,所以它们值得测试。
以下是我的系统上的一些更改,从11.4秒加速到2.8秒:
nps = 0
for i in range(1,n+1):
isp = True
for k in range(2,i):
isp = isp and (i % k != 0)
if isp: nps = nps + 1
print nps
答案 7 :(得分:0)
讽刺的是,Python是一种非常适合开发算法的语言。甚至像这样修改过的算法:
# See Thomas K for use of all(), many posters for sqrt optimization
nps = 0
for i in xrange(1, n+1):
if all(i % k for k in xrange(2, 1 + int(i ** 0.5))):
nps += 1
大约在一秒钟内运行。像这样的代码:
def eras(n):
last = n + 1
sieve = [0,0] + range(2, last)
sqn = int(round(n ** 0.5))
it = (i for i in xrange(2, sqn + 1) if sieve[i])
for i in it:
sieve[i*i:last:i] = [0] * (n//i - i + 1)
return filter(None, sieve)
更快。或者尝试these。
问题是,python通常足够快以设计您的解决方案。如果它的生产速度不够快,可以使用numpy或Jython来提高性能。或者将它移动到编译语言,随身携带你在python中学习的算法观察结果。
答案 8 :(得分:-5)
是的,Python是您遇到的最慢的实用语言之一。 While
循环比for i in xrange()
略快,但最终Python总是比其他任何东西慢得多。
Python有它的位置:原型理论和思想,或者在任何快速生成代码的能力比代码性能更重要的情况下。
Python是一种脚本语言。不是编程语言。