Python内存不足时如何分块将组合数据写入文本文件?
解决组合数据生成时的内存耗尽与写入速度问题
先直接上优化后的代码:
import itertools import hashlib import time import re # 预编译正则表达式,提升匹配替换效率 removechars1 = ["(", ")", "'", ",", " "] pattern1 = re.compile('[' + ''.join(removechars1) + ']') removechars2 = [",", " ", "-"] pattern2 = re.compile('[' + ''.join(removechars2) + ']') chars = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'] numbers_list = range(0,25) # 无需转成list,range本身支持迭代 chunk_size = 10000 # 每攒够10000行就写入一次,可根据内存情况调整 temp_rows = [] t0 = time.time() with open('data.txt', 'w', encoding='utf-8') as f: for combination in itertools.combinations_with_replacement(chars, 10): # 直接拼接组合字符,避免元组转字符串带来的多余符号 combo_str = ''.join(combination) for A in numbers_list: pure = f"{A}:{combo_str}" # 优化:现在pure里无多余括号引号,无需再用pattern1替换 B = pure B1 = [ord(char) - 96 for char in B.lower()] B2 = str(B1) B3 = pattern2.sub('', B2) C = hashlib.sha256(B.encode('utf-8')).hexdigest() C1 = [ord(char) - 96 for char in C.lower()] C2 = str(C1) C3 = pattern2.sub('', C2) # 提前构造好最终写入的行格式,减少后续字符串操作 row_str = f"{A},{B3[:10]},{C3[:10]}" temp_rows.append(row_str) # 达到块大小就批量写入 if len(temp_rows) >= chunk_size: f.write('\n'.join(temp_rows) + '\n') temp_rows.clear() # 清空临时列表释放内存 # 写入剩余未达块大小的行 if temp_rows: f.write('\n'.join(temp_rows) + '\n') tdelta = time.time() - t0 print(f"总耗时:{tdelta:.2f}秒")
关键优化点说明
分块写入:用
temp_rows临时存储指定数量的行,攒够阈值就一次性写入文件,写完清空列表。既避免了全量数据占满内存,又减少了IO系统调用次数(比逐行写入效率高很多)。chunk_size可根据你的内存情况调整,比如改成20000或5000,找到内存占用和速度的平衡点。预编译正则:提前用
re.compile编译正则表达式,避免每次re.sub时重复编译,提升字符串处理速度。优化字符串拼接:原代码中
str(combination)会生成带括号、引号的字符串,后续还要额外替换。现在直接用''.join(combination)得到纯字符拼接结果,省掉了一步正则替换操作。提前格式化行内容:用f-string直接构造最终要写入的行格式,避免后续对列表转字符串再做多次
replace,减少冗余操作。精简无用变量:删除原代码中未使用的
B4、C4变量,减少内存占用和无效计算。用range替代list(range):
numbers_list直接用range(0,25)即可,range是惰性迭代对象,无需转成list占用额外内存。
额外建议
如果组合数量极大,还可以尝试:
- 全程依赖itertools的惰性迭代特性,不存储任何多余数据,只处理当前块内容。
- 若CPU性能充足,可尝试多进程并行生成数据(每个进程写入单独文件,最后合并),但需注意文件写入的线程安全问题。新手建议先掌握分块写入,再考虑并行优化。
内容的提问来源于stack exchange,提问作者Juan Soto Valdez
相关产品推荐
相关产品推荐

