加速 urlib.urlretrieve
speeding up urlib.urlretrieve
我正在从网上下载图片,结果我需要下载很多图片。我正在使用以下代码片段的一个版本(实际上循环我打算下载的链接和下载图片:
import urllib
urllib.urlretrieve(link, filename)
我每 15 分钟下载大约 1000 张图片,根据我需要下载的图片数量来看,速度非常慢。
为了效率,我每 5 秒设置一次超时(还有很多下载持续时间更长):
import socket
socket.setdefaulttimeout(5)
除了运行计算机集群上并行下载的工作,有没有办法让图片下载更快/更有效率?
我上面的代码非常幼稚,因为我没有利用多线程。显然需要 url 个请求才能得到响应,但没有理由在代理服务器响应时计算机无法发出进一步的请求。
做下面的调整,你可以提高10倍的效率——还有更多的方法可以提高效率,比如scrapy。
要添加多线程,使用 multiprocessing 包执行如下操作:
1) 将url检索封装在一个函数中:
import import urllib.request
def geturl(link,i):
try:
urllib.request.urlretrieve(link, str(i)+".jpg")
except:
pass
2) 然后创建一个包含所有 url 以及您想要的下载图片名称的集合:
urls = [url1,url2,url3,urln]
names = [i for i in range(0,len(urls))]
3) 从 multiprocessing 包中导入 Pool class 并使用这样的 class 创建一个对象(显然,您会在实际程序的代码的第一行中包含所有导入):
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(100)
然后使用pool.starmap()方法并传递函数和函数的参数。
results = pool.starmap(geturl, zip(links, d))
注意:pool.starmap() 仅适用于 Python 3
当程序进入 I/O 等待时,执行将暂停,以便内核可以执行与 I/O 请求相关的低级操作(这称为 context switch)
并且在 I/O 操作完成之前不会恢复。
上下文切换是一项相当繁重的操作。它要求我们保存程序的状态(丢失我们在 CPU 级别的任何类型的缓存)并放弃使用 CPU。稍后,当我们再次被允许运行时,我们必须花时间在主板上重新初始化我们的程序并准备恢复(当然,这一切都是在幕后发生的)。
另一方面,对于 concurrency,
,我们通常有一个称为“事件循环”运行ning 的东西,它管理我们程序中到达 运行 的内容以及时间。本质上,事件循环只是一个需要 运行 的函数列表。列表顶部的函数获得 运行,然后是下一个,依此类推。
下面显示了一个简单的事件循环示例:
from Queue import Queue
from functools import partial
eventloop = None
class EventLoop(Queue):
def start(self):
while True:
function = self.get()
function()
def do_hello():
global eventloop
print "Hello"
eventloop.put(do_world)
def do_world():
global eventloop
print "world"
eventloop.put(do_hello)
if __name__ == "__main__":
eventloop = EventLoop()
eventloop.put(do_hello)
eventloop.start()
如果以上内容看起来像您可能会用到的东西,并且您还想了解 gevent,
tornado,
和 AsyncIO,
如何帮助您解决问题,请前往你的(大学)图书馆,查看 High Performance Python by Micha Gorelick and Ian Ozsvald,并阅读第 181-202 页。
注意:以上代码和文字来自提到的book。
我正在从网上下载图片,结果我需要下载很多图片。我正在使用以下代码片段的一个版本(实际上循环我打算下载的链接和下载图片:
import urllib
urllib.urlretrieve(link, filename)
我每 15 分钟下载大约 1000 张图片,根据我需要下载的图片数量来看,速度非常慢。
为了效率,我每 5 秒设置一次超时(还有很多下载持续时间更长):
import socket
socket.setdefaulttimeout(5)
除了运行计算机集群上并行下载的工作,有没有办法让图片下载更快/更有效率?
我上面的代码非常幼稚,因为我没有利用多线程。显然需要 url 个请求才能得到响应,但没有理由在代理服务器响应时计算机无法发出进一步的请求。
做下面的调整,你可以提高10倍的效率——还有更多的方法可以提高效率,比如scrapy。
要添加多线程,使用 multiprocessing 包执行如下操作:
1) 将url检索封装在一个函数中:
import import urllib.request
def geturl(link,i):
try:
urllib.request.urlretrieve(link, str(i)+".jpg")
except:
pass
2) 然后创建一个包含所有 url 以及您想要的下载图片名称的集合:
urls = [url1,url2,url3,urln]
names = [i for i in range(0,len(urls))]
3) 从 multiprocessing 包中导入 Pool class 并使用这样的 class 创建一个对象(显然,您会在实际程序的代码的第一行中包含所有导入):
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(100)
然后使用pool.starmap()方法并传递函数和函数的参数。
results = pool.starmap(geturl, zip(links, d))
注意:pool.starmap() 仅适用于 Python 3
当程序进入 I/O 等待时,执行将暂停,以便内核可以执行与 I/O 请求相关的低级操作(这称为 context switch)
并且在 I/O 操作完成之前不会恢复。
上下文切换是一项相当繁重的操作。它要求我们保存程序的状态(丢失我们在 CPU 级别的任何类型的缓存)并放弃使用 CPU。稍后,当我们再次被允许运行时,我们必须花时间在主板上重新初始化我们的程序并准备恢复(当然,这一切都是在幕后发生的)。
另一方面,对于 concurrency,
,我们通常有一个称为“事件循环”运行ning 的东西,它管理我们程序中到达 运行 的内容以及时间。本质上,事件循环只是一个需要 运行 的函数列表。列表顶部的函数获得 运行,然后是下一个,依此类推。
下面显示了一个简单的事件循环示例:
from Queue import Queue
from functools import partial
eventloop = None
class EventLoop(Queue):
def start(self):
while True:
function = self.get()
function()
def do_hello():
global eventloop
print "Hello"
eventloop.put(do_world)
def do_world():
global eventloop
print "world"
eventloop.put(do_hello)
if __name__ == "__main__":
eventloop = EventLoop()
eventloop.put(do_hello)
eventloop.start()
如果以上内容看起来像您可能会用到的东西,并且您还想了解 gevent,
tornado,
和 AsyncIO,
如何帮助您解决问题,请前往你的(大学)图书馆,查看 High Performance Python by Micha Gorelick and Ian Ozsvald,并阅读第 181-202 页。
注意:以上代码和文字来自提到的book。