Python 模块 aiohttp_多线程

上次进行网站检测的时候说到如果网站太多检测太慢怎么办,这个问题解决方法有很多种,比如多线程、多进程、异步 IO,我们首先看一下这三者的区别。

Python 模块 aiohttp_多进程_02



概述


首先我们看一下多进程、多线程、异步 IO,三者的区别。多进程顾名思义就是多个进程处理任务,多线程顾名思义就是多个线程处理任务,不管是多线程还是多进程,设置多少个线程或者进程是一个大难题!多了,系统资源消耗过高;少了,并发性就不够了。那么,有没有什么办法可以减少大量进程或者线程的创建产生的大量内存占用?其实是有的,就是利用所谓的线程池或者进程池;既然减少了创建和销毁对象产生的开销,那么进程或者线程切换的开销有没有办法减少呢?其实是有的,我们直接使用异步 IO 就可以了,异步 IO 实际上是异步非阻塞 IO,就是让保证一个线程或者进程在当前的 IO 请求还未完成的时候去执行其他任务,既不需要申请大量的系统资源,也不会产生阻塞,因此异步 IO 成了加快检测速度的首选。

仅仅知道这些停留在理论还不够,我们还需要知道 Python 的异步 IO 相关模块,这样的模块非常多,比如 aiohttp、gevent……因为我这里是为了加速网站请求,要求一个单位时间内请求大量的网站,所以在这里我选择 aiohttp 这个模块。


同步耗时


我们先来测试一下不使用异步 IO 处理上次讲网站检测的那些网站检测完成需要多久时间,还是上次的代码,我在这里只给出需要修改的代码,首先从 time 模块导入一个名叫 time 的函数(即 from time import time),然后直接在 if __name__ == '__main__' 里面改成如下所示就行了:

if __name__ == '__main__':
start = time()
website_detection = WebsiteDetection()
website_detection.filter()
website_detection.detect()
website_detection.save()
print(time()-start)

运行结果如图所示。

Python 模块 aiohttp_多进程_03


异步耗时


在讲解异步耗时之前,我们首先需要把代码中的 detect 方法改成异步,这太简单了,直接给出修改后的完整代码。

from asyncio import get_event_loop
from time import time
from aiohttp import ClientSession
from redis.client import Redis


class WebsiteDetection:
def __init__(self):
self.websites = open('websites.txt').readlines()
self.status_code_score = {'5': 0, '4': 1, '3': 2, '2': 3}
self.website_score = {}

async def detect(self):
async with ClientSession(headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239'
'.132 Safari/537.36 QIHU 360SE'})as session:
for website in self.websites:
print(website)
async with session.get(website)as response:
self.website_score[website] = self.status_code_score[str(response.status)[0]]

def filter(self):
self.websites = {'/'.join(website.strip('\n').split('/', maxsplit=3)[:-1])+'/'for website in self.websites}

def save(self):
redis = Redis()
for website, score in self.website_score.items():
redis.zadd('websites', website, score)
redis.connection_pool.disconnect()


if __name__ == '__main__':
start = time()
website_detection = WebsiteDetection()
website_detection.filter()
get_event_loop().run_until_complete(website_detection.detect())
website_detection.save()
print(time()-start)

运行结果如图所示。

Python 模块 aiohttp_redis_04

和同步相比差了没多少,但是确实可以发现异步的效率要比同步高,为什么这里差了没多少主要是因为网站数量太少了,异步和同步并没什么太大的区别,如果有几千个甚至几万个网站可能差距就出来了。

今天的文章有不懂的可以后台回复“加群”,备注:小陈学Python,不备注可是会被拒绝的哦~!



Python 模块 aiohttp_redis_05

Python 模块 aiohttp_redis_06





Python 模块 aiohttp_多进程_07