5

サーバーから.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のサイズだけ増加することです。メモリが再びクリアされないため、アプリが大量のメモリを使用することになります。

これは、ファイルの保存方法、またはrequests.sessionの動作に関係していると思います。

助言がありますか。

編集:コードは次のとおりです: https ://github.com/Simon1988/VK-Downloader

関連する部分はlib/vklib.pyにあります

4

2 に答える 2

5

ここでは、メモリ割り当てがどのように機能するかを理解していないことを除けば、実際の問題はないと思います。

Pythonがより多くのメモリを必要とする場合、PythonはOSにさらに多くのメモリを要求します。そのメモリを使用すると、通常はOSに返されません。代わりに、後のオブジェクトのためにそれを保持します。

したがって、最初の10MB mp3を開くと、メモリ使用量はたとえば3MBから13MBになります。次に、そのメモリを解放しますが、まだ13MBです。次に、2番目の10MB mp3を開きますが、同じメモリを再利用するため、13MBのままです。等々。

コードでは、ダウンロードごとにスレッドを作成しています。一度に5つのスレッドがあり、すべてが10MBを使用している場合、明らかに50MBを使用していることを意味します。そして、その50MBはリリースされません。ただし、それらが完了するのを待ってから、さらに5回ダウンロードすると、同じ50MBが再利用されます。

コードはスレッドの数を制限しないため、それぞれが10MB、つまりギガバイトのRAMを使用する数百のスレッドを開始することを妨げるものは何もありません(CPU速度とコンテキスト切り替えコストが不足しています)。しかし、スレッドプールに切り替えるか、あまりにも多くのダウンロードが行われている場合などにユーザーにダウンロードを開始させないようにするだけで、それは解決します。

したがって、通常、これは問題ではありません。しかし、そうであれば、それを回避する方法は2つあります。

  1. 子プロセスを作成して(たとえば、multiprocessingモジュールを介して)、メモリを大量に消費する作業を実行します。最近のOSでは、プロセスがなくなると、そのメモリが再利用されます。ここでの問題は、10MBを何度も割り当てて解放すると、システムの速度が上がるのではなく、実際に遅くなることです。プロセスの起動コスト(特にWindowsの場合)により、システムはさらに悪化します。したがって、おそらく、はるかに多くのジョブのバッチを子プロセスにスピンオフする必要があります。

  2. すべてを一度にメモリに読み込まないでください。ファイル全体のAPIの代わりにストリーミングAPIを使用します。の場合、これは最初のリクエストでrequests設定し、通常は、にアクセスする代わりに、、またはループで設定することを意味します。stream=Truer.raw.read(8192)r.iter_content()r.iter_lines()r.content

于 2013-01-11T01:16:54.977 に答える
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)
于 2013-01-11T01:07:38.720 に答える