我有一个应用程序,我使用请求从服务器下载.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"
问题是当下载完成后,python不会清除内存,因此每次下载mp3时,应用程序的内存使用量都会增加mp3的大小。内存不会再被清除,导致我的应用程序使用大量内存。
我认为这与我如何保存文件或者request.session如何工作有关。
任何建议。
编辑: 这是代码: https://github.com/Simon1988/VK-Downloader
相关部分位于lib / vklib.py
中答案 0 :(得分:4)
您可以尝试以块的形式传输内容:
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)
答案 1 :(得分:3)
我不认为这里存在实际问题,除了你不了解内存分配如何工作。
当Python需要更多内存时,它会向操作系统提出更多要求。当它完成该内存时,通常不会将其返回给操作系统;相反,它保留在以后的对象上。
所以,当你打开第一个10MB的mp3时,你的内存使用量从3MB增加到13MB。然后你释放了那个记忆,但你仍然是13MB。然后你打开第二个10MB的mp3,但它重用了相同的内存,所以你仍然是13MB。等等。
在您的代码中,您正在为每次下载创建一个线程。如果你一次有5个线程,全部使用10MB,显然这意味着你使用50MB。这50MB将不会发布。但是如果你等待它们完成,那么再做5次下载,它将再次重复使用相同的50MB。
由于你的代码没有以任何方式限制线程数,因此没有任何东西(缺乏CPU速度和上下文切换成本)来阻止你开始使用数百个线程,每个线程使用10MB,这意味着数十亿字节的RAM。但是,只是切换到一个线程池,或者如果太多人没有让用户启动更多下载,等等,将解决这个问题。
所以,通常,这不是问题。但如果是这样,有两种方法:
创建子进程(例如,通过multiprocessing
模块)进行内存占用工作。在任何现代操作系统中,当进程消失时,其内存将被回收。这里的问题是一次又一次地分配和释放10MB实际上会降低你的系统速度,而不是加速它 - 而且流程启动的成本(特别是在Windows上)会使它更糟。因此,您可能希望将更大批量的作业转移到c子进程。
不要立刻将整个内容读入内存;使用流API而不是整个文件API。使用requests
,这意味着在初始请求中设置stream=True
,然后通常在循环中使用r.raw.read(8192)
,r.iter_content()
或r.iter_lines()
而不是访问{{ 1}}。