sca*_*an_ 5 python python-requests
我有一个应用程序,我使用请求从服务器下载 .mp3 文件。
代码如下所示:
self.client = requests.session(headers={'User-Agent': self.useragent})
def download(self, url, name):
request = self.client.get(url)
with open(name, "wb") as code:
code.write(request.content)
print "done"
Run Code Online (Sandbox Code Playgroud)
问题是下载完成后,python并没有清除内存,所以每次下载mp3时,应用程序的内存使用量都会增加mp3的大小。内存不会再次被清除,导致我的应用程序使用了大量内存。
我认为这与我保存文件的方式或 requests.session 的工作方式有关。
有什么建议。
编辑:这是代码:https : //github.com/Simon1988/VK-Downloader
相关部分在 lib/vklib.py
您可以尝试分块流式传输内容:
def download(self, url, name):
request = self.client.get(url, stream=True) # `prefetch=False` for older
# versions of requests
with open(name, "wb") as code:
for chunk in request.iter_content(1024):
if not chunk:
break
code.write(chunk)
Run Code Online (Sandbox Code Playgroud)
除了您不了解内存分配的工作原理之外,我认为这里没有实际问题。
当 Python 需要更多内存时,它会要求操作系统提供更多内存。当它用完那个内存时,它通常不会将它返回给操作系统;相反,它会为以后的对象保留它。
因此,当您打开第一个 10MB mp3 时,您的内存使用量会从 3MB 增加到 13MB。然后你释放了那个内存,但你仍然是 13MB。然后你打开第二个 10MB mp3,但它重复使用相同的内存,所以你仍然是 13MB。等等。
在您的代码中,您正在为每次下载创建一个线程。如果您一次有 5 个线程,全部使用 10MB,显然这意味着您使用了 50MB。并且不会释放那 50MB。但是,如果您等待它们完成,然后再进行 5 次下载,它将再次重复使用相同的 50MB。
由于您的代码不会以任何方式限制线程数,因此没有什么(除了 CPU 速度和上下文切换成本)可以阻止您启动数百个线程,每个线程使用 10MB,这意味着数千兆字节的 RAM。但是只要切换到线程池,或者在太多下载的情况下不让用户启动更多下载等,都可以解决这个问题。
所以,通常,这不是问题。但如果是这样,有两种方法可以解决它:
创建一个子进程(例如,通过multiprocessing模块)来完成内存占用工作。在任何现代操作系统上,当一个进程消失时,它的内存会被回收。这里的问题是,一遍又一遍地分配和释放 10MB 实际上会使您的系统变慢,而不是加速——而且进程启动的成本(尤其是在 Windows 上)会使情况变得更糟。因此,您可能希望将大量作业分拆到 ac 子进程。
不要一次将整个内容读入内存;使用流式 API 而不是整个文件 API。用requests,此装置设置stream=True在初始请求,然后通常使用r.raw.read(8192),r.iter_content()或者r.iter_lines()在一个环路,而不是访问r.content。