Python 和 Go 在循环时候的性能对比

2019-07-16 23:07:22 +08:00
 Buffer2Disk

如题

两个 for 循环分别 6000 次,来嵌套; 中间休息 5 秒钟;

python 代码如下(版本 2.7 )

golang 的代码如下(版本 1.12)

python 在循环的时候,cpu 消耗 70%

golang 在循环的时候,cpu 消耗 0.6%、

这 2 个仅仅是简单的循环,性能差别就有这么大么,还是我姿势哪里不对?

7379 次点击
所在节点    程序员
54 条回复
Buffer2Disk
2019-07-17 01:26:55 +08:00
@niubee1 大佬,我的关注点其实是在 cpu 和 运行耗时 一起的

我试了下你的代码

排除掉了 range 的因素,提前创建好 list,cpu 的消耗依然不低啊(相对于 go 的 cpu 占用来说,使用的是 1 核的虚拟机)

当然我是通过 top 粗略的看了下 python 进程的 cpu 占用,可能不是那么的精确,但是能侧面反映出来大概的占用情况
Buffer2Disk
2019-07-17 01:29:04 +08:00
<img src="https://i.loli.net/2019/07/17/5d2e09582d18548030.png" alt="5555.png" title="5555.png" />
iPhoneXI
2019-07-17 01:29:47 +08:00
为什么用 2.7 这种老古董?
niubee1
2019-07-17 01:42:25 +08:00
@Buffer2Disk for 没有优化的, 提速用列表解析或者用 itertools 里的函数代替
niubee1
2019-07-17 01:44:01 +08:00
当然要说优化了就秒天秒地秒空气了那不可能,Python 确实不快, 只是优化好了并不会那么的慢, 而已。还有个办法是用 Cyhon 来优化这种纯跑圈的逻辑
blless
2019-07-17 01:46:58 +08:00
解释型语言跟编译型语言 这种对比完全没意义,编译型语言很多预编译的时候会优化一些语句,比如内联优化之类的…你的 go 的空循环可能就被优化成一个连续执行的 cpu 指令了 基本上 0 切换。不过现在晚了 也没空测试,我只是大概猜一下可能性,有兴趣可以自己找找资料
blless
2019-07-17 01:50:51 +08:00
要测试的话,我建议 for 循环里面加一些额外业务处理,然后内联优化应该可以关闭
真的想用 python 可以试试 pypy,自带 jit,直接用 docker 跑一个就可以
ysc3839
2019-07-17 02:33:26 +08:00
@Buffer2Disk 看 top 的话你怎么知道你看的时刻程序是不是在 sleep ?你给出的结果完全有可能是 Python 在循环而 Golang 在 sleep。
ysc3839
2019-07-17 02:34:54 +08:00
@Buffer2Disk 另外看到附言说是要解决性能问题,那应该测量代码的执行时间。
ysc3839
2019-07-17 02:38:58 +08:00
@Buffer2Disk 另外你所说的 CPU 消耗是 CPU 使用率,意思是一段时间内 CPU 非空闲的时间占这段时间的百分比。大部分工具是隔几秒测一下 CPU 使用率,没办法估量全部代码的执行效率。
LokiSharp
2019-07-17 08:34:27 +08:00
Go 没试过,我只知道 Python 整体比 Java 慢 10 倍
www5070504
2019-07-17 09:14:26 +08:00
猜测是 golang 可能优化到操作高速缓存或者寄存器了 python 你这样写肯定有频繁读或者写内存
xdeng
2019-07-17 09:23:03 +08:00
go for 里面没写东西可能会被优化掉的
dongxiaozhuo
2019-07-17 10:31:05 +08:00
如果以 Golang 的写法为基准,应该是 Python 里面使用 while 判断一个变量和一个数字的比较结果,例如 while i < 6000: 这样,不管使用 range 和 xrange 都是一堆数字的合集,只是类型与方式不同。
ipwx
2019-07-17 11:59:13 +08:00
Python 的 for 循环性能是不可优化的,别想了,不可能的。

去考虑如何优化 Python 的 for 循环是没有意义的,因为一个老道的 Python 程序员,不是在 sentence-level 优化 Python 程序性能的。

比如我要算向量 x + y ( for 循环裸写是 O(N)),我们会直接使用 NumPy (它是用 C 语言写的 Python 库):

import numpy as np

x = np.asarray(...)
y = np.asarray(...)
out = x + y

矩阵点积( for 循环裸写是 O(N^2)):

M = np.asarray(...)
N = np.asarray(...)
out = np.dot(M, N)

如果是可以转化成这种张量运算的,就尝试转化一下。如果不能,就上 Cython。比如 Scikit Learn 的 Tree Classifier 系列代码:

https://github.com/scikit-learn/scikit-learn/blob/7813f7efb5b2012412888b69e73d76f2df2b50b6/sklearn/tree/_tree.pyx

如果 Cython 再不行,就上 C/C++ 语言。比如 TensorFlow 一坨运算:

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/ops/

有时候偷懒,会用 JIT 引擎把 Python 代码直接在内存中即时编译成机器码,比如:

Numba: https://numba.pydata.org/
Pytorch: https://pytorch.org/docs/stable/_modules/torch/jit.html
TensorFlow: https://www.tensorflow.org/xla/jit
----

以上所有总而言之,Python 的优化方法不是去一条一条语句优化,而是直接暴力把整个 block 替换成更高效的实现。所以你考虑优化 python for 循环没有意义。作为一个 Python 程序员,你应该先考虑实现业务逻辑,然后找出真正的性能瓶颈,再考虑用高级手段(以上种种)优化它们。
ipwx
2019-07-17 12:00:50 +08:00
顺便 Cython 是一种特别发明出来的 C/Python 混合语言,即没有完全的 C 语言功能,也没有完全的 Python 功能,会经过编译器编译成本机代码。适用于 Python 写起来太慢,但是又不需要 C 语言全部功能的场景。
ipwx
2019-07-17 12:01:08 +08:00
Python 写起来太慢 -> Python 写的代码跑起来太慢。
ipwx
2019-07-17 12:04:52 +08:00
顺便 Python JIT 还有一个 PyPy,适用于网络编程。
crella
2019-07-17 12:32:44 +08:00
你应该在最内层循环加个判断或者赋值,比如 if 1 = true ; a = 1,要不然哪家语言都会优化掉。
crella
2019-07-17 12:39:13 +08:00
反正 g4560,我做文本按列切割整理保存的工作,单核,perl6 1500 行 /s,perl5 2300 行 /s,vb.net3.5 3300 行 /s,不会用 python

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

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

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

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

© 2021 V2EX