20 yield内存处理机制详解

1、生成器的内存优势:

  • 一次只处理一行数据,不会将整个文件加载到内存
  • 处理完一行后,该行的内存会被自动释放
  • 无论文件多大,内存使用量基本保持稳定

2、对比传统方法:

  • 传统方法会一次性加载整个文件到内存
  • 文件越大,内存使用量越大,可能导致内存溢出
  • 添加了对比函数,可以直观看到差异

3、逻辑解析

   yield processed  # 返回处理结果,暂停执行,等待下次调用
   # 此处是关键:yield后,前一行数据不再被引用,会被垃圾回收

 这行代码是整个内存优化的核心,它实现了"处理一行,释放一行"的机制。

4、yield的核心优势总结

  1. 惰性计算:按需生成数据,不预先加载全部内容
  1. 即时释放:处理完数据后立即释放内存
  1. 内存恒定:无论处理多大的文件,内存使用基本保持稳定
  1. 响应迅速:不需等待全部加载即可开始处理第一条数据

5、快速记忆要点

  • yield = 暂停 + 返回 + 记住位置
  • 生成器处理大文件的内存使用是恒定的,而不是随文件大小增长
  • 生成器是迭代一次性的,用完就需要重新创建
  • 生成器适合处理大数据集、流式数据和无限序列

import os  # 导入操作系统模块,用于获取进程ID
import psutil  # 导入进程状态工具,用于监控内存使用情况
import gc  # 导入垃圾回收模块,用于手动触发垃圾回收


def memory_usage():
    """返回当前Python进程的内存使用量(MB)"""
    process = psutil.Process(os.getpid())  # 获取当前进程对象
    return process.memory_info().rss / (1024 * 1024)  # 返回物理内存使用量(MB)


def process_large_file(file_path):
    """使用生成器处理大文件,展示内存使用情况"""
    print(f"开始处理前内存使用: {memory_usage():.2f} MB")

    # 定义内部生成器函数 - yield的核心应用
    def line_generator():
        """逐行读取文件的生成器函数

        优势:
        1. 一次只加载一行到内存
        2. 处理完立即释放该行内存
        3. 无论文件多大,内存使用基本恒定
        """
        with open(file_path, "r") as file:  # 打开文件,自动关闭
            for i, line in enumerate(file):  # 文件对象本身是迭代器,逐行读取
                processed = line.upper()  # 对当前行进行处理

                # 每处理10万行输出一次内存状态
                if i % 100000 == 0:
                    print(f"已处理 {i} 行, 当前内存: {memory_usage():.2f} MB")

                yield processed  # 返回处理结果,暂停执行,等待下次调用
                # 此处是关键:yield后,前一行数据不再被引用,会被垃圾回收

    # 使用生成器处理文件
    count = 0
    for _ in line_generator():  # 迭代生成器,每次获取一行
        count += 1  # 只计数,不存储结果
        # 这里不保存处理结果到列表,避免累积内存占用

    # 手动触发垃圾回收
    gc.collect()
    print(f"处理结束后内存使用: {memory_usage():.2f} MB")
    print(f"总共处理了 {count} 行")
    print("\nyield的内存优势总结:")
    print("1. 惰性计算:按需生成数据,不预先加载")
    print("2. 即时释放:处理完数据立即释放内存")
    print("3. 内存恒定:无论文件多大,内存使用基本稳定")
    print("4. 响应迅速:不需等待全部加载即可开始处理")


# 对比传统方法(可选,取消注释以运行)
def process_traditional(file_path):
    """传统方法处理文件(一次性加载全部内容)"""
    print(f"\n传统方法 - 开始前内存: {memory_usage():.2f} MB")

    # 一次性读取整个文件到内存
    with open(file_path, "r") as file:
        all_lines = [line.upper() for line in file]  # 加载并处理所有行

    count = len(all_lines)
    print(f"传统方法 - 加载全部 {count} 行后内存: {memory_usage():.2f} MB")

    # 释放内存
    del all_lines
    gc.collect()
    print(f"传统方法 - 释放后内存: {memory_usage():.2f} MB")


# 使用示例
if __name__ == "__main__":
    # 创建测试文件(如果需要)
    # with open("large_file.txt", "w") as f:
    #     for i in range(1000000):
    #         f.write(f"This is line {i} for testing memory usage with generators.\n")

    # 使用生成器处理
    process_large_file("large_file.txt")

    # 使用传统方法处理(大文件慎用)
    # process_traditional("large_file.txt")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值