一次说明白Python爬虫中多线程,多进程,异步IO编程
图/文:迷神
我们在Python爬虫中,重要的是讲究速度,如果有10万或者100万Url地址,写过爬虫的都会知道,那估计是非常慢的。我们的Python爬虫一般IO密集型业务,Python爬虫程序需要发起网络请求,必然就有网络IO阻塞,通常请求一个URL耗时要几百毫秒到几秒,逐步执行,和我们CPU那么高性能比起来,那真是天壤之别。
比如,我们Python爬虫在单线程同步爬取过程中,一个个的爬取网站所有的URL,假设100个URL,平均每个URL请求的时间是1秒,那么在单线程同步场景下,最快也需要100秒钟,才能把所有的页面爬取下来。
在网页数据爬取以后,发现在数据量不大的时候,这种普通的程序还勉强,如果想极大提高速度,做到 快速爬虫,就需要使用多线程,多进程,异步IO编程了。不过,Python中有一个臭名昭著的GIL,导致做不到真正的并行运算,多核无法真正利用起来。多线程在切换线程,还有切换成本,以及线程的创建成本。如果使用多进程,虽然能利用多核处理的优势,但是多进程的创建本城比线程更高,而IO密集型任务,CPU不是瓶颈。
鉴于此,Python3.4 还是引入了异步 asyncio 模块,增加了异步编程,跟 JavaScript 的async/await 极为类似,大大方便了异步任务的处理。异步编程使得CPU不再需要再去等待耗时的操作,而是让出CPU时间给其他任务执行,可以极大提高完成所有的任务速度。
下面,我们通过具体的小例子,来看看多线程,多进程,异步IO编程的区别:
1、普通同步,单线程阻塞
单线程版本,所有的任务,按照顺序依次等待执行。
结果如下:
可以发现,总共5个任务,他们每个任务执行时间是1秒钟,单进程阻塞时,总共耗时是5秒多一点点。
2、多线程版本任务
简单来说就是在一个进程里面,可以执行多个任务,在这里的每一个任务就是一个线程。
执行结果:
换成多线程之后,5个线程各负责一个任务。我们看到执行结果:1.0039010047912598 已经明显比第一个快很多了。即使有GIL
多进程版本任务
多进程就是你的电脑允许运行多个程序,在同一段时间里面,可以 “同时” 执行多个任务。
执行结果:
执行结果:1.7484214305877686。是不是很奇怪,使用多进程,时间比多线程更慢,为什么?因为创建进程的成本是要比线程高的,虽然,它可以利用多核CPU的优势。
异步版本多个任务
最后,我们来看看异步模式下,怎么样。
执行结果:
发现使用asyncio所花的时间是最少的。asyncio可以实现单线程并发IO操作,它没有多线程和进程的创建成本,就是在单线程环境下,切换任务,当这个任务被阻塞时,立刻切换其他任务,当前面的任务完成时,在通知它,这样效率就极大的提高了。
最后,值得一说的就是一个不错的HTTP框架:aiohttp,它是一个基于asyncio实现的非常强大的HTTP框架,很值得学习哦。