python 纯加减运算慢

2016 年 4 月 2 日
 simon4545

Python 代码: import time a=time.time() i=0 for i in xrange(95550000): i +=100 i -=100 print i print time.time()-a

运行结果: 95549999 15.253000021

得到的不是 95550000 编译成了 Pyc 也一样的结果

但换成 Node.js 会快 100 倍都不止 var a=new Date(); var i; for(i = 0; i < 95550000; ++i) {    i += 100; i -= 100; } console.log(i) console.log((new Date())-a)

结果: 95549999 0.21799993515

我试了 pypy,性能和 node.js 接近

6064 次点击
所在节点    Python
28 条回复
koykoi
2016 年 4 月 2 日
这种 hot spot 代码不正是 JIT 的优势吗
clino
2016 年 4 月 2 日
nodejs 应该和 pypy 一样都用了 jit 吧?
clino
2016 年 4 月 2 日
我这里的结果是
-在循环里算两个+-耗时 15.1 秒
-在循环里算一个+耗时 9.89 秒
-循环里 pass 耗时 3.72 秒
BOYPT
2016 年 4 月 2 日
大概是因为 python 里面的整数是 immutable 的对象,你这样的操作就是重复生成对象和回收对象,所以效率较低;大概使用 numbers 模块里面功能会有改善。
josephok
2016 年 4 月 2 日
用 python3 试试
ikw
2016 年 4 月 2 日
本来就应该是 9554999 的吧?
python3 是:
95549999
10.84103798866272
Zzzzzzzzz
2016 年 4 月 2 日
光这个 xrange 就得两三秒.
要改进性能的话把这段代码抽出来上 Cython , i = 0 前面加 cdef long, 秒变毫秒级.
simon4545
2016 年 4 月 2 日
python3 执行也是一样的,而且还要更久一点
有没有 jit 居然相差那么大
realpg
2016 年 4 月 2 日
1. python 内 xrange(3)的结果是 0,1,2
2. 这种场景就是 JIT 的性能强悍啊

realpg@TestingServer17:/tmp/demo$ python python.py
95549999
15.7798058987
realpg@TestingServer17:/tmp/demo$ pypy python.py
95549999
0.574637174606
realpg@TestingServer17:/tmp/demo$ /usr/local/php5/bin/php php.php
95550000
7.9244079589844
realpg@TestingServer17:/tmp/demo$ /usr/local/php7/bin/php php.php
95550000
3.8246450424194


python2.7 python.py 代码同楼主

php.php 代码
<?php
$time_start = microtime(true);
for ($i=0;$i<95550000;$i++) {
$i+=100;
$i-=100;
}
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "{$i}\n{$time}\n";
slixurd
2016 年 4 月 2 日
居然连 microbench 之类的工具都没用,在这裸写。。。。
bigtan
2016 年 4 月 2 日
用 Python ,执行效率一般难以成为瓶颈,因为,他可以通过别的优化手段轻松的达到 C-level 的执行效率。
theoractice
2016 年 4 月 2 日
@bigtan 42.7ns ?表示震惊
zhuangzhuang1988
2016 年 4 月 2 日
没 jit 就得这么慢, 虽然里面有一些 intern 缓存优化。但是对这些纯计算的没啥鸟用。。
bigtan
2016 年 4 月 2 日
@theoractice 有缓存的可能,你可以看 best case 。 42.7ns*24.87=1061.9ns ,不过也足够惊人的了。
est
2016 年 4 月 2 日
其实 python 加减乘除不慢, for 比较慢。
mathgl
2016 年 4 月 2 日
这种代码, jit 稍微优化一下就是常数了。
Zzzzzzzzz
2016 年 4 月 2 日
@theoractice
@bigtan

倒没那么夸张, Cython 现在对 range 和 xrange 有优化, 会直接转成循环, 以前那种 for i from 0<=i<95550000 的方言被废了, 然后默认的编译参数又是-O2, 直接把循环这部分给优化掉了,等于什么都没做直接给 i 赋值了
SlipStupig
2016 年 4 月 3 日
每次+一次就是内存申请一次啊,而且你用 for 就变成了直接 sum 回快多了 sum(xrange(95550000)),时间明显减少太多了

3 function calls in 1.140 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.140 1.140 test.py:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 1.140 1.140 1.140 1.140 {sum}
simon4545
2016 年 4 月 3 日
@est 我后面也试了,正如你所说的一样。
能请教一下原因么?
pynix
2016 年 4 月 3 日
不可变对象,一直在申请和释放内存。

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

https://study.congcong.us/t/268116

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

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

© 2021 V2EX