如何限制python3请求中的下载速度?
我使用请求在运行Linux的小型嵌入式设备上下载一个大的~50MiB文件 将文件写入附加的MMC 不幸的是,MMC的写入速度低于网络速度,我看到内存消耗增加,在一些情况下,我甚至让内核无法处理页面。。。错误 该设备只有128MiB RAM 我使用的代码是: 对于requests.getURL,stream=True为r: 如果r.status_代码!=200: log.errorf'???下载返回{r.status_code}' 返回-偏移量+r.状态\ U代码 大小=0 使用opensfn,“wb”作为fo: 对于r.iter\u contentchunk\u size=4096中的块: fo.writechunk siz+=lenchunk 返回大小 如何在写入MMC时临时停止服务器如何限制python3请求中的下载速度?,python,python-requests,bandwidth-throttling,Python,Python Requests,Bandwidth Throttling,我使用请求在运行Linux的小型嵌入式设备上下载一个大的~50MiB文件 将文件写入附加的MMC 不幸的是,MMC的写入速度低于网络速度,我看到内存消耗增加,在一些情况下,我甚至让内核无法处理页面。。。错误 该设备只有128MiB RAM 我使用的代码是: 对于requests.getURL,stream=True为r: 如果r.status_代码!=200: log.errorf'???下载返回{r.status_code}' 返回-偏移量+r.状态\ U代码 大小=0 使用opensfn,“
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)
您可以将其重写为协同程序
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服务器支持,则可以请求仅下载大文件的一部分,然后逐部分浏览整个文件 请看,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)
由于您的问题是内存,您可能希望停止服务器立即向您发送整个文件,因为这肯定会被设备上的某些代码缓冲。除非您可以让请求删除它接收的部分数据,否则这将始终是一个问题。请求下游的附加缓冲区将不会有帮助。如果web服务器支持,您可以请求仅下载大文件的一部分,然后逐部分浏览整个文件 请看,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)
由于您的问题是内存,您可能希望停止服务器立即向您发送整个文件,因为这肯定会被设备上的某些代码缓冲。除非您可以让请求删除它接收的部分数据,否则这将始终是一个问题。请求下游的附加缓冲区将没有帮助。您可以尝试使用此bash命令减小TCP接收缓冲区的大小:
echo 'net.core.rmem_max=1000000' >> /etc/sysctl.conf
1MB,你可以调整这个
这就避免了在流程的这个阶段出现巨大的缓冲区积累
然后编写代码,使其仅从TCP堆栈读取,并以指定的间隔写入MMC,以防止缓冲区在系统中的其他位置累积,例如MMC写入缓冲区-例如@e3n的答案
希望这会导致数据包被丢弃,然后在缓冲区再次打开时由服务器重新发送。您可以尝试使用此bash命令减小TCP接收缓冲区的大小:
echo 'net.core.rmem_max=1000000' >> /etc/sysctl.conf
1MB,你可以调整这个
这就避免了在流程的这个阶段出现巨大的缓冲区积累
然后编写代码,使其仅从TCP堆栈读取,并以指定的间隔写入MMC,以防止缓冲区在系统中的其他位置累积,例如MMC写入缓冲区-例如@e3n的答案
希望这会导致数据包被丢弃,然后在缓冲区再次打开时由服务器重新发送。这是否回答了您的问题@python_user:除非我遗漏了什么,否则那里的代码与我已经在使用的代码是等价的。我的问题是磁盘写入部分比从网络获取慢。显然,在这种情况下,请求或下面的东西会不断分配内存来缓冲尚未处理的传入数据。我需要一种减缓来源的方法,例如:延迟发送帧确认也相关:这是否回答了您的问题@python_user:除非我遗漏了什么,否则那里的代码与我已经在使用的代码是等价的。我的问题是磁盘写入部分比从网络获取慢。显然,在这种情况下,请求或下面的东西会不断分配内存来缓冲尚未处理的传入数据。我需要一种方法来减缓来源,例如:延迟发送帧确认也相关:谢谢。我肯定会尝试这个方法,但我不明白它将如何减慢这个过程。我的写操作已经太慢了,怎么能让它们更慢呢?显然,请求不会等待我轮询r.iter_内容来填充它。我需要在请求代码中插入一个睡眠调用,如果我没弄错的话。是的,你可以在调用nextobj for循环之前添加睡眠调用。请稍等片刻,我正在重新写作it@ZioByte它现在完成了,你可以使用它了。它也可以解决你的记忆问题,因为它正在一块一块地写one@e3n但是如果你睡觉,操作系统会不会只是在内存中的某个地方缓冲接收到的数据包,从而保持内存问题?@Anonymous1847我在文件处理方面没有太多经验。但是在这里,我们产生块并手动使用它,所以我认为不应该有任何与内存相关的问题。睡眠是一种选择
纳尔。我不推荐,但也许@Ziobyte设备速度慢,所以他可能需要它。我肯定会尝试这个方法,但我不明白它将如何减慢这个过程。我的写操作已经太慢了,怎么能让它们更慢呢?显然,请求不会等待我轮询r.iter_内容来填充它。我需要在请求代码中插入一个睡眠调用,如果我没弄错的话。是的,你可以在调用nextobj for循环之前添加睡眠调用。请稍等片刻,我正在重新写作it@ZioByte它现在完成了,你可以使用它了。它也可以解决你的记忆问题,因为它正在一块一块地写one@e3n但是如果你睡觉,操作系统会不会只是在内存中的某个地方缓冲接收到的数据包,从而保持内存问题?@Anonymous1847我在文件处理方面没有太多经验。但是在这里,我们产生块并手动使用它,所以我认为不应该有任何与内存相关的问题。睡眠是可选的。我不推荐使用它,但可能@Ziobyte设备速度慢,所以他可能需要它。请尝试我的升级,但我的服务器既不支持范围,也不支持重新启动:这很不幸。如果你只想把文件下载到磁盘上,可以考虑不要使用请求,但是可以通过OS.Stor或子进程等调用CURL之类的外部工具。CURL支持带宽限制,参见很好的尝试我投票,但是我的服务器既不支持范围也不支持重新启动:这是不幸的。如果你只想把文件下载到磁盘上,可以考虑不要使用请求,但是可以通过OS.Stor或子进程等调用CURL等外部工具。有趣的是,我当前的值no/etc/sysctl.confat非常低:net.core.rmem_max=180224。我想在基本TCP之上,在我的应用程序级别之下,有什么东西在做缓冲。@ZioByte可能是python库在缓冲什么东西。也许有减少缓冲区大小的选项?或者你可以尝试另一个图书馆。嗯。。。有趣的是,我当前的值no/etc/sysctl.confat非常低:net.core.rmem_max=180224。我想在基本TCP之上,在我的应用程序级别之下,有什么东西在做缓冲。@ZioByte可能是python库在缓冲什么东西。也许有减少缓冲区大小的选项?或者你可以尝试另一个图书馆。