目录

Python-性能优化从入门到精通的实用指南

Python 性能优化:从入门到精通的实用指南

Langchain系列文章目录

python系列文章目录

19-Python 性能优化:从入门到精通的实用指南



前言

Hey,你有没有遇到过这样的情况:代码跑得太慢,CPU 风扇狂转,甚至内存直接爆满?在 Python 开发中,性能问题是个绕不过去的坎儿。无论是处理大数据、写爬虫,还是开发 Web 应用,优化性能都能让你的程序更快、更省资源。这篇文章的目标很简单:带你从零开始,搞懂影响 Python 性能的因素,学会几个超实用的优化技巧,还要教你怎么用 timeit 模块测测代码到底有多快。不管你是刚入门的小白,还是有点经验的开发者,这里都有干货等着你!

本文会聊三大块:

  • 影响 Python 性能的“幕后黑手”:时间复杂度和空间复杂度。
  • 优化代码的“锦囊妙计”:避免重复计算、减少 IO 操作。
  • 性能检测的“秘密武器”: timeit 模块。

准备好了吗?咱们这就开始!


一、影响 Python 性能的因素

性能优化得先知道问题出在哪儿,对吧?Python 虽然简单好用,但有些地方不注意就会拖慢速度。这部分咱们聊聊两个核心因素:时间复杂度和空间复杂度。

1.1 时间复杂度

时间复杂度听起来有点学术,其实就是“你的代码跑起来需要多久”。它跟数据量大小直接挂钩,数据越多,影响越明显。

1.1.1 为什么时间复杂度重要?

简单说,时间复杂度决定了一个算法的效率。比如你在列表里找个数,数据量小还好,可要是列表里有几百万条数据,效率低的算法能让你等到怀疑人生。

  • 举个例子 :用列表和集合找数字的区别。

    # 列表找数字,时间复杂度 O(n)
    my_list = [1, 2, 3, 4, 5]
    if 3 in my_list:  # 得一个个检查
        print("找到啦!")
    
    # 集合找数字,时间复杂度 O(1)
    my_set = {1, 2, 3, 4, 5}
    if 3 in my_set:  # 直接定位,超快
        print("找到啦!")
  • 关键点 :列表是线性查找,时间复杂度是 O(n);集合用哈希表,平均时间复杂度是 O(1)。数据量越大,差距越明显。

1.1.2 怎么优化时间复杂度?

  • 建议 :需要频繁查找时,用集合( set )或字典( dict )代替列表。
  • 场景 :比如去重、查重这种操作,集合简直是神器。

1.2 空间复杂度

时间跑得快还不够,内存用得少也很重要。空间复杂度就是“你的代码占了多少内存”。

1.2.1 空间复杂度为啥关键?

Python 自动管理内存,但用错了数据结构,内存照样吃紧。比如存一堆数字,用列表和生成器差别可不小。

  • 举个例子

    # 列表存一百万个数,全都加载到内存
    my_list = [i for i in range(1000000)]  # 内存占用大
    
    # 生成器,边用边生成,内存几乎不占
    my_gen = (i for i in range(1000000))  # 超省空间
  • 关键点 :列表把所有数据都存下来,空间复杂度 O(n);生成器只存当前值,空间复杂度接近 O(1)。

1.2.2 怎么优化空间复杂度?

  • 建议 :大数据场景下,优先用生成器或迭代器。
  • 场景 :比如读取大文件、处理流数据,用生成器能省下不少内存。

二、Python 性能优化技巧

知道了影响性能的因素,咱们得动手优化代码。这部分分享两个超实用的技巧:避免重复计算和减少 IO 操作。

2.1 避免重复计算

重复计算就像你炒菜时把同一个葱花切了十遍,太浪费时间!Python 里有些操作可以提前做好,省下不少力气。

2.1.1 使用缓存机制

缓存就是把算过的结果存起来,下次直接拿来用。Python 自带一个神器: functools.lru_cache

  • 代码示例 :优化递归计算斐波那契数列。

    from functools import lru_cache
    
    @lru_cache(maxsize=128)  # 缓存最多 128 个结果
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-1) + fibonacci(n-2)
    
    print(fibonacci(50))  # 超快!
  • 关键点 :没缓存时,递归会重复算好多次;加了缓存,直接查表,时间从“天文数字”变成“秒级”。

  • 场景 :递归函数、频繁调用的计算任务。

2.1.2 预计算和惰性计算

  • 预计算 :提前把结果算好,比如程序启动时把常用数据准备好。

  • 惰性计算 :用到时再算,用生成器就是典型例子。

    def lazy_range(n):
        i = 0
        while i < n:
            yield i  # 每次只生成一个数
            i += 1
    
    for num in lazy_range(1000):  # 按需取值
        print(num)
  • 建议 :不常用的数据用惰性计算,常用的小数据用预计算。

2.2 减少 IO 操作

IO 操作(比如读文件、发网络请求)特别慢,减少它的次数能让代码飞起来。

2.2.1 批量处理数据

别一行行读文件,一次性读完再处理效率更高。

  • 代码示例

    # 逐行读,IO 次数多
    def process(line):
        print(line)
    
    with open('file.txt', 'r') as f:
        for line in f:  # 每次都调用 IO
            process(line)
    
    # 一次性读,IO 次数少
    with open('file.txt', 'r') as f:
        content = f.read()  # 一次读完
        lines = content.splitlines()
        for line in lines:
            process(line)
  • 关键点 :批量操作把多次 IO 变成一次,速度提升明显。

  • 场景 :读写大文件、数据库操作。

2.2.2 使用异步 IO

网络请求多的时候,等一个完再发下一个太慢,用异步 IO 可以同时处理。

  • 代码示例 :用 asyncio 抓网页。

    import asyncio
    import aiohttp
    
    async def fetch_url(url):
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                return await response.text()
    
    async def main():
        urls = ['http://example.com', 'http://example.org']
        tasks = [fetch_url(url) for url in urls]
        results = await asyncio.gather(*tasks)
        print(results[0][:100])  # 只打印前 100 个字符
    
    asyncio.run(main())
  • 关键点 :异步 IO 让多个请求并行,特别适合爬虫或高并发任务。

  • 场景 :网络密集型任务。


三、使用 timeit 模块测量代码性能

优化完代码,怎么知道效果咋样?用 timeit 模块测一测就知道了!

3.1 timeit 模块简介

timeit 是 Python 自带的小工具,专门测小段代码的运行时间。它会重复跑代码取平均值,结果很靠谱。

3.1.1 为什么用 timeit

手动用 time.time() 测时间不准,因为系统负载会干扰。 timeit 跑很多次,数据更稳定。

3.2 如何使用 timeit 测量代码性能

3.2.1 命令行使用 timeit

直接在终端跑,适合快速测试。

  • 示例 :测列表推导式的速度。

    python -m timeit "sum([i for i in range(1000)])"
  • 输出 :类似“1000 loops, best of 5: 123 usec per loop”,表示平均每次多久。

  • 建议 :调试小代码时用这个,简单又快。

3.2.2 在代码中使用 timeit

想在脚本里测?也很简单。

  • 代码示例

    import timeit
    
    def my_function():
        return sum([i for i in range(1000)])
    
    # 跑 100 次,测总时间
    execution_time = timeit.timeit(my_function, number=100)
    print(f"总耗时: {execution_time} 秒")
  • 关键点number 是运行次数,自己调,别设太大跑不动。

  • 场景 :对比不同实现方案的性能。


四、总结

本文聊了 Python 性能优化的三大块:

  • 影响因素 :时间复杂度管速度,空间复杂度管内存,选对数据结构很关键。
  • 优化技巧 :避免重复计算用缓存和生成器,减少 IO 用批量和异步。
  • 测量工具timeit 帮你量化优化效果。

希望你看完能有所收获,赶紧把这些技巧用到自己的代码里吧!有什么问题,随时问我哦~