·· 写过爬虫的都知道,爬虫的性能瓶颈在于IO,因为爬虫是一个IO密集型业务,程序需要发起网络请求,必然就有IO阻塞,通常请求一个URL耗时要几百毫秒到几秒不等,而我们的CPU处理速度惊人,两者的速度就好比乌龟跟火箭的差别。在单线程同步阻塞程序中,如果要获取一个网站所有的URL,假设100个URL,平均每个URL请求的时间是1秒,那么在单线程同步场景下,最快也需要100秒钟,才能把所有的页面爬取下来。
于是,我们想到了更好的一种办法就是采用多线程或者多进程,但是由于在Python中臭名昭著的GIL,导致做不到真正的并行运算,在同一时间内,就算有多核CPU,也无法被利用起来,这样虽然能做到并发,但是没法并行,在单个CPU里切换线程,还有切换成本,以及线程的创造成本。如果使用多进程,虽然能利用多核处理的优势,但是多进程的创建本城比线程更高,而IO密集型任务,CPU不是瓶颈。
所以,后来 Python 引入了异步编程,异步编程使得CPU不再需要再去等待耗时的操作,而是让出CPU时间给其他任务执行,这样假如有100个任务,每个任务是1秒钟,就可以做到理论上只需要1秒钟就可以完成所有的任务。
来看看这几个简单的例子,你能体会到他们之间的差别
单线程阻塞版本
总共5个任务,每个任务执行时间是1秒钟,单进程阻塞时,总共耗时是5秒多。
多线程版本
换成多线程之后,5个线程各负责一个任务,全部完成最后只花了1秒多一点时间,所以,对于阻塞性任务,例如IO密集型任务,即使有GIL,还是能发挥多线程的作用的,毕竟,时间花在IO等待上,如果是CPU密集型任务,也是白搭。
多进程版本
讽刺的是,使用多进程,时间比多线程更慢,为什么?因为创建进程的成本是要比线程高的,虽然,它可以利用多核CPU的优势,但是在这里,用不上,就好比杀鸡用牛刀一样,大材小用,还提高了成本。
异步
最后,我们用单线程异步模型来看看时间是多少
最后,发现使用asyncio所化的时间是最少的。因为它没有多线程和进程的创建成本,就是在单线程环境下,切换任务,当这个任务被阻塞时,立刻切换其他任务,当前面的任务完成时,在通知它。
学习Python和网络爬虫关注公众号:datanami
领取专属 10元无门槛券
私享最新 技术干货