如果你需要在Python中处理一个大的 JSON 文件,会很容易出现耗尽内存的情况。即使原始数据大小小于内存容量,Python 也会进一步增加内存使用量。这意味着程序会在与磁盘交互时处理缓慢,或在内存不足时崩溃。
一种常见的解决方案是流解析,也就是惰性解析、迭代解析或分块处理。让我们看看如何将此技术应用于 JSON 处理。
问题:Python中加载JSON内存效率低
我们使用这个大小为24MB的JSON文件来举例,它在加载时会对内存产生明显的影响。这个JSON对象是在GitHub中,用户对存储库执行操作时的事件列表:
[{"id":"2489651045","type":"CreateEvent","actor": {"id":665991,"login":"petroav","gravatar_id":"","url":"https://api.github.com/users/petroav","avatar_url":"https://avatars.githubusercontent.com/u/665991?"},"repo": {"id":28688495,"name":"petroav/6.828","url":"https://api.github.com/repos/petroav/6.828"},"payload": {"ref":"master","ref_type":"branch","master_branch":"master","description":"Solution to homework and assignments from MIT's 6.828 (Operating Systems Engineering). Done in my spare time.","pusher_type":"user"},"public":true,"created_at":"2015-01-01T15:00:00Z"}, ... ]
我们的目标是找出给定用户在与哪些存储库进行交互。下面是一个简单的 Python 程序:
import json with open("large-file.json", "r") as f: data = json.load(f) user_to_repos = {} for record in data: user = record["actor"]["login"] repo = record["repo"]["name"] if user not in user_to_repos: user_to_repos[user] = set() user_to_repos[user].add(repo)
输出结果是一个用户名映射到存储库名称的字典。我们使用 Fil 内存分析器运行它时,可以发现内存使用的峰值达到了124MB,还可以发现两个主要的内存分配来源:
- 读取文件
-
将生成的字节解码为 Unicode 字符串
但我们加载的原始文件是24MB。一旦我们将它加载到内存中并将其解码为文本 (Unicode)Python 字符串,它需要的空间远远超过 24MB。这是为什么?
扩展知识:Python字符串的内存表示
Python字符串在表示时会被更少使用内存的方法优化。每个字符串都有固定的开销,如果字符串可以表示为 ASCII,则每个字符只使用一个字节的内存。如果字符串使用更多扩展字符,则每个字符可能使用4个字节。我们可以使用 sys.getsizeof() 查看一个对象需要多少内存:
>>> import sys >>> s = "a" * 1000 >>> len(s) 1000 >>> sys.getsizeof(s) 1049 >>> s2 = "❄" + "a" * 999 >>> len(s2) 1000 >>> sys.getsizeof(s2) 2074 >>> s3 = "
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/9874/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料
查 看2022高级编程视频教程免费获取