从S3加载json.gz到Python时程序无响应,求排查方案
问题分析
你的代码看似用了stream=True,但实际上没有实现真正的流式处理,这是导致程序卡住的核心原因:
r.content会一次性将整个3.1GB的压缩文件下载到内存中,大文件的网络下载本身耗时极久,还会占用大量内存资源。gzip.decompress(r.content)会把整个压缩包解压后全部加载到内存,3.1GB的gzip文件解压后通常会膨胀数倍(甚至几十GB),直接撑爆内存,导致系统调度卡顿,程序看起来像卡住。- 代码中未导入
json模块(你用了j.loads但未定义j),不过你提到没报错,应该是代码漏写了导入,但这不是卡住的关键问题。
优化建议
1. 实现真正的流式处理(分块下载+解压)
利用requests的流式响应结合gzip.GzipFile边下载边解压,避免一次性加载大文件到内存:
import json import gzip import requests def parse(url: str): raw_data = [] with requests.get(url, stream=True) as r: # 流式读取并解压数据 with gzip.GzipFile(fileobj=r.raw) as gz_file: # 逐行解析解压后的JSON数据 for line in gz_file: raw_data.append(json.loads(line.decode("utf-8"))) return raw_data raw_data = parse('https://s3-eu-west-1.amazonaws.com/path/of/bucket.json.gz')
2. 避免将所有数据存入内存
如果解压后的数据量极大,把所有内容存入列表会再次占用大量内存,可按需处理:
- 逐行写入本地文件(JSON Lines格式):
import json import gzip import requests def parse(url: str, output_path: str): with requests.get(url, stream=True) as r: with gzip.GzipFile(fileobj=r.raw) as gz_file: with open(output_path, 'w', encoding='utf-8') as f: for line in gz_file: data = json.loads(line.decode("utf-8")) json.dump(data, f) f.write('\n') parse('https://s3-eu-west-1.amazonaws.com/path/of/bucket.json.gz', 'output.jsonl')
- 用生成器逐行返回数据,按需迭代处理:
import json import gzip import requests def parse(url: str): with requests.get(url, stream=True) as r: with gzip.GzipFile(fileobj=r.raw) as gz_file: for line in gz_file: yield json.loads(line.decode("utf-8")) # 按需处理每一条数据 for item in parse('https://s3-eu-west-1.amazonaws.com/path/of/bucket.json.gz'): # 这里可以做数据清洗、入库等操作 print(item)
3. 优化网络访问效率
- 如果你所在区域和S3的eu-west-1区域距离较远,网络延迟会拖慢下载速度。可以考虑使用AWS SDK(如boto3)直接访问S3,SDK会自动优化请求路径和重试机制:
import json import gzip import boto3 from io import BytesIO s3 = boto3.client('s3') bucket_name = 'your-bucket-name' key = 'path/of/bucket.json.gz' def parse_s3(bucket, key): response = s3.get_object(Bucket=bucket, Key=key) with gzip.GzipFile(fileobj=BytesIO(response['Body'].read())) as gz_file: for line in gz_file: yield json.loads(line.decode("utf-8")) for item in parse_s3(bucket_name, key): # 处理单条数据 pass
4. 监控程序运行状态
在循环中加入进度打印,确认程序是否在正常运行而非真的卡住:
import json import gzip import requests def parse(url: str): raw_data = [] line_count = 0 with requests.get(url, stream=True) as r: with gzip.GzipFile(fileobj=r.raw) as gz_file: for line in gz_file: raw_data.append(json.loads(line.decode("utf-8"))) line_count += 1 if line_count % 1000 == 0: print(f"已处理 {line_count} 行数据") return raw_data
内容的提问来源于stack exchange,提问作者bbgghh
相关产品推荐
相关产品推荐

