1、生成器的内存优势:
- 一次只处理一行数据,不会将整个文件加载到内存
- 处理完一行后,该行的内存会被自动释放
- 无论文件多大,内存使用量基本保持稳定
2、对比传统方法:
- 传统方法会一次性加载整个文件到内存
- 文件越大,内存使用量越大,可能导致内存溢出
- 添加了对比函数,可以直观看到差异
3、逻辑解析
yield processed # 返回处理结果,暂停执行,等待下次调用
# 此处是关键:yield后,前一行数据不再被引用,会被垃圾回收
这行代码是整个内存优化的核心,它实现了"处理一行,释放一行"的机制。
4、yield的核心优势总结
- 惰性计算:按需生成数据,不预先加载全部内容
- 即时释放:处理完数据后立即释放内存
- 内存恒定:无论处理多大的文件,内存使用基本保持稳定
- 响应迅速:不需等待全部加载即可开始处理第一条数据
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")