算 1 到 10 亿的所有自然数的和,c 用时 4.4's, java 用时 3.8's,python 用时 302.9's,已吓尿,求解释

2014-10-18 16:37:36 +08:00
 MonkLuf
算1到10亿的所有自然数的和,c用时4.4's, java用时3.8's,python用时302.9's。

吓尿!!!

java居然这么快,居然比c都快!!python居然慢了将近100倍也太夸张了吧!!这个速度突然毁掉了我的世界观。。。。。

求懂java的人带详细理由的告诉我为什么java会这么快,python为何慢这么多(慢得太离谱了。。。)
12971 次点击
所在节点    问与答
106 条回复
bigtan
2014-10-18 18:53:02 +08:00
import numpy as np
%timeit np.sum(np.arange(1,1000000000))
1 loops, best of 3: 5.12 s per loop

不用pypy用numpy也可以跑到一个数量级
xavierskip
2014-10-18 19:18:37 +08:00
In [12]: start = time.time();sum(xrange(1,100000001));print time.time()-start
1.27270293236


慢吗?
ifishman
2014-10-18 19:30:25 +08:00
@xavierskip 确实慢,1秒和1/20000秒,慢了不只一点点。算法的不同而已。其实我不懂python……:-P
cloverstd
2014-10-18 19:34:04 +08:00
> python sum.py
sum_raw: 500000000500000000, use time: 77.362965107's
sum_1: 500000000500000000, use time: 78.8294119835's
sum_2: 500000000500000000, use time: 46.696573019's
sum_3: 500000000500000000, use time: 12.4079239368's

pypy 快好多啊
> pypy sum.py
sum_raw: 500000000500000000, use time: 0.948999881744's
sum_1: 500000000500000000, use time: 1.04911208153's
sum_2: 500000000500000000, use time: 1.19244813919's
sum_3: 500000000500000000, use time: 1.18416213989's
dant
2014-10-18 19:51:44 +08:00
来个 Ruby 的。
lushl9301
2014-10-18 19:56:21 +08:00
@cloverstd pypy真是快。。。

to others:
我这里同样java最快,c其次。
对于c来说,++i 要比 i++快一点;i 从 1000000000减到 0 比从0加到1000000000稍微快一点。
对于java不成立。

python的确很慢。
猜测原因是Cpython的int是immutable的。

每次sum += i都会放一个新的内存位置给他。
再加上垃圾处理机制,就会更慢了。。

可以用31楼的sum_1来测试。1到100加和,每次print id(s)看一下。
ovear
2014-10-18 20:07:04 +08:00
我也来一个版本,运行时决定累加数目

Scanner scanner = new Scanner(System.in);
int target = scanner.nextInt();
for (int c = 0; c < 11; c++) {
long startTime = System.currentTimeMillis(); //获取开始时间
long i = 0, sum = 0;
while (i++ < target) {
sum += i;
}
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.format("sum: %d, use time: %f's\r\n", sum,
(endTime - startTime) / 1000.0);
}
//使用sum的方法
long startTime = System.nanoTime(); //获取开始时间
long result = ((1L + target) * target) / 2L; //求和公式
long endTime = System.nanoTime(); //获取结束时间
System.out.format("sum: %d, use time: %f'ms(may be inaccurate due to the kernel)\r\n", result,
(endTime - startTime) / 1000000.0);

output

1000000000
sum: 500000000500000000, use time: 0.647000's
sum: 500000000500000000, use time: 0.647000's
sum: 500000000500000000, use time: 0.648000's
sum: 500000000500000000, use time: 0.645000's
sum: 500000000500000000, use time: 0.645000's
sum: 500000000500000000, use time: 0.643000's
sum: 500000000500000000, use time: 0.644000's
sum: 500000000500000000, use time: 0.642000's
sum: 500000000500000000, use time: 0.642000's
sum: 500000000500000000, use time: 0.644000's
sum: 500000000500000000, use time: 0.645000's
sum: 500000000500000000, use time: 0.000293'ms(may be inaccurate due to the kernel)
ovear
2014-10-18 20:14:38 +08:00
@ovear nanotime不准。。之后都是0.0000了。。奇葩
NahN2Regh
2014-10-18 20:41:26 +08:00
rust开启优化后, 与C没差别了, 都很快:

编译器 优化 时间
gcc -- real:0m3.930s, user:0m3.916s, sys:0m0.008s
gcc -O1 real:0m0.630s, user:0m0.624s, sys:0m0.000s
gcc -O2 real:0m0.002s, user:0m0.000s, sys:0m0.000s
rustc -- real:0m4.172s, user:0m4.000s, sys:0m0.020s
rustc --opt-level=1 real:0m0.003s, user:0m0.000s, sys:0m0.000s

gcc 的版本是4.9.1
rust版本是0.12

源代码:
[code]
$ cat sum.c
#include <stdio.h>

int main(int argc, char *argv[]) {

long i = 0;
long s = 0;
long limit = 1000000000;
while (i < limit) {
s = s + i;
i = i + 1;
}
printf("%ld\n", s);

return 0;
}
[/code]
[code]
$ cat sum.rs

fn main() {
let mut i = 0i64;
let mut s = 0i64;
let limit = 1000000000i64;
while i < limit {
s = s + i;
i = i + 1;
}
println!("{}", s);
}
[/code]
Shared
2014-10-18 21:39:12 +08:00
如果要用 Python 做这种事情要么用 PyPy,要么写个 C 扩展呗。
P.S. 这种比较好没意思
davidli
2014-10-18 21:47:39 +08:00
Python下能用内置函数的情况下一定要用内置函数.
ant_sz
2014-10-18 22:08:05 +08:00
我觉得从上面的回答已经可以看得出来:

语言本身的性能决定了运行时间的下限,但是程序员写程序的水平决定了运行时间的上限。

同样一个功能,不同的人写出来性能能有百倍的差距。

因此,一些情况下,语言本身的性能并没有开发效率和易用性更重要。
icedx
2014-10-18 22:26:37 +08:00
efen
2014-10-18 22:51:06 +08:00
@icedx 一本正经的跑题,哈哈哈
ggarlic
2014-10-18 23:21:53 +08:00
@lushl9301 现在的编译器,++i跟i++产生的汇编是一样的了,不信你-S一下。
takato
2014-10-18 23:28:51 +08:00
我觉得用O(n)的算法去解决一个O(1)就能解决的问题,真是用牛刀了- -
efen
2014-10-18 23:38:52 +08:00
Lisp大法好 ( ̄(工) ̄)

尾递归版本46s,普通递归版本把8g内存全吃光,跑了7分多钟没结果,哈哈哈
wdlth
2014-10-19 00:10:39 +08:00
C的那段程序结果

gcc 4.8.3 不加参数
sum: 500000000500000000, time used: 2.358622 's
gcc -O3
sum: 500000000500000000, time used: 0.424286 's
Intel C Compiler 14.0不加参数
sum: 500000000500000000, time used: 0.412634 's
Intel C Compiler -O3
sum: 500000000500000000, time used: 0.407397 's
Intel C Compiler -O3 -mtune=corei7 -march=corei7
sum: 500000000500000000, time used: 0.375456 's

Intel大 好
iam36
2014-10-19 00:45:57 +08:00
仅用数学运算来比对太片面了。
webjin
2014-10-19 00:58:42 +08:00
不错哦

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/139818

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX