簡體   English   中英

如何限制 python3 請求中的下載速度?

[英]How to limit download speed in python3 requests?

我正在使用請求在運行 Linux 的小型嵌入式設備上下載一個大(~50MiB)文件。

文件將寫入附加的 MMC。

不幸的是,MMC 寫入速度低於凈速度,我看到 memory 消耗增加,在某些情況下,我什至遇到 kernel “無法處理頁面......”錯誤。

設備只有 128MiB RAM。

我正在使用的代碼是:

            with requests.get(URL,  stream=True) as r:
                if r.status_code != 200:
                    log.error(f'??? download returned {r.status_code}')
                    return -(offset + r.status_code)
                siz = 0
                with open(sfn, 'wb') as fo:
                    for chunk in r.iter_content(chunk_size=4096):
                        fo.write(chunk)
                        siz += len(chunk)
                return siz

寫入 MMC 時如何暫時停止服務器?

                if r.status_code != 200:
                    log.error(f'??? download returned {r.status_code}')
                    return -(offset + r.status_code)
                siz = 0
                with open(sfn, 'wb') as fo:
                    for chunk in r.iter_content(chunk_size=4096):
                        fo.write(chunk)
                        siz += len(chunk)
                return siz

您可以將其重寫為協程

import requests

def producer(URL,temp_data,n):
    with requests.get(URL,  stream=True) as r:
        if r.status_code != 200:
            log.error(f'??? download returned {r.status_code}')
            return -(offset + r.status_code)
        for chunk in r.iter_content(chunk_size=n):
            temp_data.append(chunk)
            yield #waiting to finish the consumer
            

def consumer(temp_data,fname):
    with open(fname, 'wb') as fo:
        while True:
            while len(temp_data) > 0:
                for data in temp_data:
                    fo.write(data)
                    temp_data.remove(data) # To remove it from the list
                    # You can add sleep here
                    yield #waiting for more data


def coordinator(URL,fname,n=4096):
    temp_data = list()
    c = consumer(temp_data,fname)
    p = producer(URL,temp_data,n)
    while True:
        try:
            #getting data
            next(p)
        except StopIteration:
            break
        finally:
            #writing data
            next(c)

這些都是您需要的功能。 調用這個

URL = "URL"
fname = 'filename'
coordinator(URL,fname)

如果 web 服務器支持http Range字段,您可以請求僅下載大文件的一部分,然后逐步瀏覽整個文件。

看看這個問題,James Mills 給出了以下示例代碼:

from requests import get

url = "http://download.thinkbroadband.com/5MB.zip"
headers = {"Range": "bytes=0-100"}  # first 100 bytes

r = get(url, headers=headers)

由於您的問題是 memory,因此您需要阻止服務器一次向您發送整個文件,因為這肯定會被您設備上的某些代碼緩沖。 除非您可以讓請求刪除它收到的部分數據,否則這將始終是個問題。 requests下游的額外緩沖區將無濟於事。

您可以嘗試使用此 bash 命令減小 TCP 接收緩沖區的大小:

echo 'net.core.rmem_max=1000000' >> /etc/sysctl.conf

(1 MB,你可以調整這個)

這將阻止在該過程的這個階段建立巨大的緩沖區。

然后編寫代碼僅從 TCP 堆棧讀取並以指定的時間間隔寫入 MMC 以防止緩沖區在系統的其他地方建立,例如 MMC 寫緩沖區 - 例如@e3n 的答案。

希望這會導致數據包被丟棄,然后在緩沖區再次打開時由服務器重新發送。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM