首页
学习
活动
专区
圈层
工具
发布

Python太慢?这4个提速神技让你代码快到飞起!

大家好,欢迎来到 Crossin 的编程教室。

作为每天都在用 Python 工作的开发者,我最常听到大家的吐槽就是:“Python 写起来是真爽,但跑起来也是真慢!”

尤其是在处理一些大量计算或者跑数据的时候,看着控制台半天不跳下一个进度条,恨不得进去推它一把。

其实,很多时候并不是 Python 不行,而是我们使用的“姿势”不对。今天 Crossin 就来跟大家分享 4 个实战中非常管用的提速技巧,直接上代码!

1. 别再死磕 for 循环了,用 NumPy 降维打击

这是很多刚进阶的同学最容易踩的坑:处理一大堆数据时,下意识地就写个 for 循环遍历。

Python 解释器跑这种原生的 for 循环开销极大。遇到数值计算,能用 NumPy 向量化解决的,绝不用 for 循环。 NumPy 底层是 C 语言,它能一次性把操作打在整个数组上。

标准写法:

import time

def slow_sum(n):   a = list(range(n))   b = list(range(n))   c = []   for i in range(len(a)):       c.append(a[i] + b[i])   return c

# 跑 1000 万次,测测看start = time.time()slow_sum(10**7)print(f"原生循环耗时: {time.time() - start:.2f}s")

加速写法:

import timeimport numpy as np

def fast_sum(n):   a = np.arange(n)   b = np.arange(n)   return a + b

start = time.time()fast_sum(10**7)print(f"NumPy 向量化耗时: {time.time() - start:.4f}s")

运行结果:

原生循环耗时:1.82s

NumPy 向量化耗时:0.12s

千万级数据下,NumPy 比原生列表循环快了15倍。

2. 实在绕不开循环?加个 @njit 装饰器救命

有些复杂的业务逻辑,比如带有复杂判断条件的数值模拟,真的没法直接用 NumPy 拼出来,必须得写 for 循环怎么办?

这时候,祭出神器 Numba。它是一个 JIT(即时编译器),作用非常粗暴:把你的 Python 函数直接翻译成机器码。

用法超级简单,只需要引入库,并在函数头上加一行 @njit。

标准写法:

import time

def check_logic(n):   res = 0   for i in range(n):       if i % 3 == 0:           res += i   return res

start = time.time()check_logic(10**8)print(f"原生 Python 耗时: {time.time() - start:.2f}s")

加速写法:

import timefrom numba import njit

@njit  # 只需要这一个装饰器def check_logic_fast(n):   res = 0   for i in range(n):       if i % 3 == 0:           res += i   return res

# 第一次运行会有编译时间,之后起飞start = time.time()check_logic_fast(10**8)print(f"Numba JIT 耗时: {time.time() - start:.2f}s")

运行结果:

原生 Python 耗时: 6.54s

Numba JIT 耗时: 0.42s

Numba 第一次运行时要编译,优化不明显,之后的运行速度大约提升了15倍。

3. 多核 CPU 别闲着,多进程 multiprocessing 跑起来

众所周知,Python 有个叫 GIL(全局解释器锁)的玩意儿,导致单进程下多线程没法同时利用多核 CPU。

如果你需要处理比如:大规模图片压缩、海量文件解析这种“吃 CPU”(计算密集型)的任务,别犹豫,直接上多进程,强行把你的 8 核、10 核 CPU 榨干。

标准写法:

import time

deftask(n):returnsum(i * i for i inrange(n))

start = time.time()[task(10**7) for _ inrange(4)]print(f"单进程顺序执行: {time.time() - start:.2f}s")

加速写法:

import timeimport multiprocessing

deftask(n):returnsum(i * i for i inrange(n))

if __name__ == "__main__":   start = time.time()with multiprocessing.Pool(processes=4) as pool:       pool.map(task, [10**7] * 4)print(f"4进程并行执行: {time.time() - start:.2f}s")

运行结果:

单进程顺序执行: 3.98s

4进程并行执行: 1.23s

千万级数据下,4进程并行比单进程快了3倍多。

4. 终极偷懒大招:代码一行不改,换 PyPy 跑

如果你上面这些都不想搞,或者这是一个纯粹用 Python 写的庞大项目,有没有“物理外挂”?

有的,直接把执行命令里的 python 换成 pypy。

PyPy 是自带了 JIT 编译器的 Python 替代品。你不需要改动任何一行代码。

举个例子,一个算斐波那契数列的脚本 fib.py:

# fib.pydef fib(n):   if n < 2: return n   return fib(n-1) + fib(n-2)

import timestart = time.time()fib(36)print(f"执行耗时: {time.time() - start:.2f}s")

你平时这么跑:python fib.py

执行耗时:3.16s

现在这么跑:pypy3 fib.py

执行耗时:0.21s

纯 Python 代码的逻辑,换个“发动机”,就获得了15倍的速度提升。不过要注意,pypy3运行环境需要额外安装,并且如果你的项目重度依赖某些特定的 C 扩展库,兼容性需要提前测试一下。

总结:

写 Python 遇到性能瓶颈了,可以参考这个思路:

玩数据矩阵:优先想办法用 NumPy。

死磕计算循环:用 Numba 加速试试。

批量粗活累活:开 多进程 一起上。

祖传老代码:丢给 PyPy 碰碰运气。

但也要注意,优化是有成本的,别为了快而快,先把功能实现好。否则过早的优化是万恶之源!

大家平时在写代码时还踩过哪些性能的坑?或者有什么压箱底的优化绝活?欢迎在评论区留言聊聊。

如果本文对你有帮助,欢迎点赞、评论、转发。你们的支持是我更新的动力~

感谢转发点赞的各位~

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OAflmBm5Kck0CzfYGTxcBlvw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券