ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python性能优化实战

Python性能优化实战 Python 性能优化实战10 个让程序快 10 倍的技巧全部真机跑给你看写 Python 第十五年我见过太多人一上来就用multiprocessing开多进程、上 PyPy、买更高配的服务器结果 profile 一跑发现瓶颈就是自己写的那段循环。性能优化不是玄学也不是让你去学 C 扩展——大部分时候换个数据结构、用对内置函数速度就已经提了几十倍。这篇文章里的每一个技巧我都在本机 PyCharmPython 3.12里真实跑了一遍下面的截图全是 Run 窗口的输出。橙色标签是技巧编号上面是代码下面是真机 benchmark 数据。你可以直接照着敲数字不会骗人。一、字符串拼接别在循环里用 这是我最早踩过的坑。在循环里用s str(i)Python 每拼一次就要重新分配一块内存把旧字符串拷过去复杂度直接变成 O(n²)。10 万次循环花了 0.78 秒而.join()只花了 0.01 秒——快了 73 倍。原理很简单join 一次性算好总长度分配一块内存把所有字符串依次填进去只拷一次。记住循环里拼字符串永远用 join()。二、列表推导式一行顶三行还更快在 Python 3.12 里列表推导和 append 循环的差距已经缩小到 1.1 倍左右不像早年差好几倍。但列表推导式依然是首选——因为它更短、更清晰、更不容易出错。性能只是副产品可读性才是主要原因。别为了性能去写更难读的代码。列表推导式快不快是其次它让代码意图一目了然。三、集合查找从 O(n) 到 O(1) 的暴力美学这个数据是我自己跑出来都愣了一下的1000 次查找列表in花了 6.9 秒集合in花了 0.000058 秒——快了将近 12 万倍。原因是数据结构本质不同列表是顺序存储in要从头扫到尾O(n)集合是哈希表in直接算哈希定位O(1)。只要你需要频繁判断在不在第一反应就是转成 set。数据量越大差距越离谱。四、生成器100 万个数字只占 0.2 KB列表推导[x*x for x in range(1000000)]占了 8 MB 内存而生成器(x*x for x in range(1000000))只占 0.2 KB——差了四万倍。生成器不把所有结果存下来而是你要一个它算一个用完就扔。如果你只是遍历一遍、不需要随机访问就别用列表用生成器。处理大文件、大数据流的时候这一个习惯就能避免 OOM。五、递归加缓存从 1.4 秒到 0.000017 秒斐波那契数列的递归写法fib(35)裸奔要 1.37 秒因为它重复算了海量子问题。加个备忘录memo dict同一参数只算一次——0.000017 秒快了 6 万倍。Python 标准库直接给了你functools.lru_cache装饰器一行搞定。只要你看到递归函数里有相同参数反复计算的味道先加缓存再说。这是算法层面的优化比任何语法糖都猛。六、内置函数 sumC 写的就是比你快手写循环累加 100 万个数字要 0.057 秒内置sum()只要 0.005 秒——快了 10.9 倍。原因很简单sum()在 C 层实现没有 Python 字节码的循环开销。同理max()、min()、sorted()、any()、all()这些内置函数都比你手写 for 循环快一个数量级。能用内置函数就别自己造轮子。七、Counter统计词频别再手写 if/else 了统计一个列表里每个元素出现多少次新手写法是建个 dict 然后 if/else 判断。collections.Counter直接帮你干了这件事快 3.2 倍代码还短一半。Python 标准库里有一堆这种专门干某件事的工具Counter、defaultdict、OrderedDict、deque……用熟它们你的代码会短一半速度还更快。八、f-string不是为了优雅是为了快f-string 和拼接的差距在 Python 3.12 里已经不大了1.2 倍但 f-string 依然是首选——它不用你手动str()转类型也不用数有几个加号。fname{name}, age{age}一眼看过去就知道输出长什么样。%格式化和.format()现在基本可以淘汰了。f-string 是 Python 3.6 以来最大的语法福利没有理由不用。九、deque从 list 头部删元素等于在排队这个数据是最夸张的10 万次list.pop(0)花了 14.2 秒而deque.popleft()只花了 0.004 秒——快了 3356 倍。为什么因为 list 的底层是动态数组你从头部删一个元素后面所有元素都要往前挪一位这是 O(n) 的操作。10 万次 pop(0) 就是 O(n²)。而 deque 是双向链表两头增删都是 O(1)。只要你需要先进先出的队列就用 deque别用 list。十、循环外提不变的东西别在循环里算这个提升只有 1.7 倍但它是最容易被忽略的优化。如果你在循环体里写了len(data) * 2这种不随循环变量变化的计算Python 会老老实实算 10 万次。把它提到循环外面算一次速度立刻上来。编译器有时候会帮你做这件事叫 loop invariant code motion但 Python 的解释器不会。养成习惯写完循环看一眼哪些计算每次都一样提出来。总结性能优化就这三板斧这 10 个技巧跑完我把规律总结成三句话选对数据结构set 查存在、dict 查键、deque 做队列、生成器省内存——数据结构选对了性能问题解决一半。用内置函数和标准库sum、Counter、lru_cache、join——这些都是 C 实现的比你手写循环快一个数量级。别在循环里做傻事别拼字符串、别从头部删元素、别重复算不变量——循环是性能重灾区多看一眼。性能优化不是过早优化而是知道什么时候该优化。先用time和timeit量出来哪里慢再对症下药。如果你连瓶颈在哪都不知道优化就是瞎猜。这 10 个技巧你要是都记住了写 Python 的效率能上一个台阶。哪个技巧你之前没注意到评论区聊聊我看看还有哪些坑可以一起踩。meit 量出来哪里慢再对症下药。如果你连瓶颈在哪都不知道优化就是瞎猜。这 10 个技巧你要是都记住了写 Python 的效率能上一个台阶。哪个技巧你之前没注意到评论区聊聊我看看还有哪些坑可以一起踩。
返回列表