引用页
概念
假如你有手上有4个任务需要分配给甲、乙、丙、丁去完成,你有两种方式,第一种:将第一个任务分配给甲后等他处理完之后告诉你处理后的结果,此时再将第二个任务分配给乙,以此类推下去,如果甲做事的结果对你交代给乙的任务有关联,就必须选择这种方式;
但是如果甲乙丙丁的任务没有任何关联,那么你可以考虑以一种更加快捷的方式来分发任务,你可能会想到,直接将4个任务逐个分发出去,谁处理完后你就先阅读谁的结果,这样的效率是不是提升了好几倍呢?
-
将如上方式与多线程区分开,因为在分配任务的时候是你独自完成的,所以我们把这种概念称之为,
非阻塞IO(协程)
-
http连接池:对于相同socket
(协议://ip:端口)
会使用已有连接进行请求,以充分利用现有的资源,减少请求时间
阻塞IO示例
- 普通阻塞IO请求,请求消耗的时间最长,并且每个请求都使用新的socket,耗时约1.2秒
import requests
res = requests.get("http://www.docrepository.org/")
res1 = requests.get("http://www.docrepository.org/books/faceVerif")
res2 = requests.get("http://hunandalong.com/contact.html")
连接池示例
- 如下同一个域名下的不同页面就共用了同一个socket,第一个和第二个都使用了61959的本机端口
http = urllib3.PoolManager(retries=2, timeout=10, num_pools=200, maxsize=200)
res = http.request("GET", "http://www.docrepository.org/")
print('请求1号域名:' + str(len(http.pools)))
res1 = http.request("GET", "http://www.docrepository.org/books/faceVerif")
print('请求另一个1号域名:' + str(len(http.pools)))
res2 = http.request("GET", "http://hunandalong.com/contact.html")
print('请求2号域名:' + str(len(http.pools)))
非阻塞IO与线程池并用
- 使用aiohttp的Session(),该对象内置了线程池,如下61303-61307被重复使用了
- 因为请求了两次,如果只看第一次的三个请求,你会发现3.40557-3.789853(第67个包)结束,总共耗时:
0.384秒
import aiohttp
async def send(client, url):
async with client.get(url) as resp:
result = await resp.text()
async def send_message():
async with aiohttp.ClientSession() as client:
url_list = [
'http://www.docrepository.org/',
'http://www.docrepository.org/books/faceVerif',
'http://www.docrepository.org/books/mybatis-plus',
'http://www.docrepository.org/books/vue-markdown',
"http://hunandalong.com/"
]
tasks = list()
for url in url_list:
tasks.append(asyncio.create_task(send(client, url)))
await asyncio.wait(tasks)
# 此处重复一次该请求,这样就会利用到本机的socket,因为内置http连接的为keepalive,并且超时为15秒,在15秒内都是可以复用连接
taskss = list()
for url in url_list:
taskss.append(asyncio.create_task(send(client, url)))
await asyncio.wait(taskss)
asyncio.run(send_message())