You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用requests下载大文件并传入subprocess标准输入的问题求助

使用requests流式下载大文件并传递给subprocess的优化方案

我之前也踩过这个坑!你写的那段代码逻辑上没问题,但速度慢到让人抓狂,核心问题出在r.raw的默认行为上——它的缓冲区太小了,导致子进程(比如wc)一直在频繁处理 tiny 的数据块,光是系统调用的开销就把速度拖垮了。

问题根源

requests.get(..., stream=True)返回的r.raw是urllib3.response.HTTPResponse对象,它默认的读取块非常小,而且没有开启高效缓冲。当你直接把它传给subprocess.Popen的stdin时,子进程会不断触发小数据读取操作,频繁的用户态/内核态切换严重拉低了整体效率。

优化方案

下面两种方法都能解决这个问题,核心思路都是增大数据传输的块大小,减少IO操作的次数:

方法1:手动分块读取并写入子进程

用requests的iter_content方法指定合适的块大小,分块把数据写入子进程的标准输入:

import requests
import subprocess

# 替换成你的大文件URL
url = "http://example.com/large-file"
# stream=True开启流式下载
r = requests.get(url, stream=True)
# 关键:自动解压服务器返回的压缩内容(比如gzip)
r.raw.decode_content = True

# 启动子进程,这里以wc为例
p = subprocess.Popen(["wc"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# 设置块大小,建议64KB~1MB之间,根据内存情况调整
chunk_size = 64 * 1024
for chunk in r.iter_content(chunk_size=chunk_size):
    if chunk:  # 过滤空块
        p.stdin.write(chunk)

# 关闭stdin,告诉子进程输入结束
p.stdin.close()
# 获取子进程输出
output, _ = p.communicate()
print(output.decode("utf-8"))

方法2:用shutil高效复制文件对象

shutil.copyfileobj是Python标准库提供的高效文件对象复制工具,它会自动使用合适的缓冲区大小,代码更简洁:

import requests
import subprocess
import shutil

url = "http://example.com/large-file"
r = requests.get(url, stream=True)
r.raw.decode_content = True

p = subprocess.Popen(["wc"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# 用copyfileobj完成高效数据传输,也可以指定bufsize参数调整缓冲区
shutil.copyfileobj(r.raw, p.stdin)
p.stdin.close()
output, _ = p.communicate()
print(output.decode("utf-8"))

额外注意事项

  • r.raw.decode_content = True一定要加!如果服务器返回的是压缩格式(比如gzip),这个设置会自动解压,避免传给子进程压缩后的原始数据。
  • 块大小不用盲目调大,一般64KB就能显著提升速度,太大可能会占用过多内存,反而影响性能。
  • 如果网络不稳定,建议添加异常处理(比如捕获requests.exceptions.RequestException),避免中途崩溃。

内容的提问来源于stack exchange,提问作者Congbin Guo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:32:59