如何优化使用json.dump将字典列表写入文件的实现,提升大数据量写入效率
性能瓶颈核心原因
原实现的最大性能损耗来自 每写入1条数据就执行1次文件打开/关闭操作,文件IO是操作系统级的高开销操作,5000条数据对应5000次open/close调用,再加上单条写入的频繁刷盘开销,自然耗时极高。你认为的「并行写入同一文件」属于优化误区,多线程/进程写同一份文件会出现内容穿插、覆盖的问题,额外加锁反而会进一步降低性能,优化IO操作就能解决绝大多数性能问题。
优化方案
方案1:批量分组写入(改造成本最低、性能提升最明显)
按file_limit的大小把原列表拆分成多个子组,每个子组对应1个输出文件,每个文件仅打开1次,内存中提前拼接好所有行内容后一次性写入。5000条数据仅需要打开100次文件,耗时可降至秒级。
import json from itertools import islice # 按文件条目上限拆分大列表为多个子组 chunk_size = file_limit all_chunks = iter(lambda: list(islice(iter(all_response_dict_list), chunk_size)), []) for chunk in all_chunks: current_file = self.generate_new_micro_file_name() # 单个文件仅打开一次,批量写入所有对应条目 with open(current_file, 'w', encoding='utf-8') as f: lines = [json.dumps(item, ensure_ascii=False) + '\n' for item in chunk] f.writelines(lines) self.propagate_log_msg(f'wrote {len(chunk)} records ')
方案2:单文件缓冲写入(适合单条字典体积大、内存不足的场景)
不需要提前拼接整个子组的内容到内存,单个文件周期内只打开一次,逐条写入内存缓冲区,满file_limit后关闭文件切换新文件即可,性能同样远高于原实现。
import json file_limit_counter = 0 current_file = self.generate_new_micro_file_name() f = open(current_file, 'w', encoding='utf-8') try: for response_dict in all_response_dict_list: if file_limit_counter == file_limit: self.propagate_log_msg(f'wrote {file_limit} records ') f.close() current_file = self.generate_new_micro_file_name() f = open(current_file, 'w', encoding='utf-8') file_limit_counter = 0 f.write(json.dumps(response_dict, ensure_ascii=False) + '\n') file_limit_counter += 1 finally: f.close() self.propagate_log_msg(f'wrote {file_limit_counter} records for last file')
额外提速技巧
- 序列化时给
json.dumps添加ensure_ascii=False参数,非ASCII字符(比如中文)序列化速度更快,输出文件体积也更小 - 数据量超过10万条时,可以用第三方库
ujson替换标准库json,序列化速度能提升2~5倍,用法完全兼容,仅需要将import json改为import ujson as json即可 - 确实需要并行处理时,可以让每个进程/线程写入独立的文件,避免同文件写入冲突,处理完成后再合并文件即可
内容的提问来源于stack exchange,提问作者Kulasangar
相关产品推荐
相关产品推荐

