Python下载会话时请求不清除内存

时间:2013-01-11 01:03:58

标签: 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"

问题是当下载完成后,python不会清除内存,因此每次下载mp3时,应用程序的内存使用量都会增加mp3的大小。内存不会再被清除,导致我的应用程序使用大量内存。

我认为这与我如何保存文件或者request.session如何工作有关。

任何建议。

编辑: 这是代码: https://github.com/Simon1988/VK-Downloader

相关部分位于lib / vklib.py

2 个答案:

答案 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。但是,只是切换到一个线程池,或者如果太多人没有让用户启动更多下载,等等,将解决这个问题。

所以,通常,这不是问题。但如果是这样,有两种方法:

  1. 创建子进程(例如,通过multiprocessing模块)进行内存占用工作。在任何现代操作系统中,当进程消失时,其内存将被回收。这里的问题是一次又一次地分配和释放10MB实际上会降低你的系统速度,而不是加速它 - 而且流程启动的成本(特别是在Windows上)会使它更糟。因此,您可能希望将更大批量的作业转移到c子进程。

  2. 不要立刻将整个内容读入内存;使用流API而不是整个文件API。使用requests,这意味着在初始请求中设置stream=True,然后通常在循环中使用r.raw.read(8192)r.iter_content()r.iter_lines()而不是访问{{ 1}}。