Python异步协程(asyncio详解)
作者:互联网
1. 什么是协程(Coroutines)
在了解异步之前,先大致了解一下什么是协程。
网上的讲法有各种:
- 协程是一种比线程更加轻量级的存在
- 协程是一种用户级的轻量级线程
- 协程,又称微线程
大体看过之后就感觉,我好像懂了,有好像没懂,个人感觉有点晕乎乎的,没太明白。(PS:可能是我个人智商没够不能快速领悟的原因)
个人理解(PS:不涉及其本质来源、底层实现、仅仅就着这个异步爬虫来说):协程就像一条带应急车道的高速公路(具体作用就是让任务有了暂停切换功能)
线程:把需要执行的任务比作汽车,线程就像一条单行且只有一条道的高速公路,只有等前一辆车到达终点后面的车才能出发,如果其中一辆出了事情停在了路上,那么这俩车后面的车就只能原地等待直到它恢复并到达终点才能继续上路。
协程:把需要执行的任务比作汽车,协程就像一条带应急车道的高速公路,如果汽车在中途出了问题就可以直接到一边的应急车道停下处理问题,下一辆车可以直接上路,简单来说就是可以通过程序控制哪辆车行驶,哪辆车在应急车道休息。
2.同步跟异步
同步跟异步是两个相对的概念:
同步:意味着有序
异步:意味着无序
小故事模拟事件:
小明在家需要完成如下事情:
- 电饭锅煮饭大约30分钟
- 洗衣机洗衣服大约40分钟
- 写作业大约50分钟
在同步情况下:小明需要电饭锅处等待30分钟、洗衣机处等待40分钟、写作业50分钟,总计花费时间120分钟。
在异步情况下:小明需要电饭锅处理并启动花费10分钟、洗衣机处理并启动花费10分钟,写作业花费50分钟,总计花费时间70分钟。
即同步必须一件事情结束之后再进行下一件事,异步是可以在一件事情没结束就去处理另外一件事情了。
注意:此处异步比同步耗时更短是有前提条件的!要是I/O阻塞才可以(说人话:类似电饭锅煮饭,电饭锅可以自行完成这种的)
如果把条件中的电饭锅换成柴火,洗衣机换成搓衣板,那么事情就只能一件一件完成了,两者耗时相近。
3.asyncio异步协程
asyncio即Asynchronous I/O是python一个用来处理并发(concurrent)事件的包,是很多python异步架构的基础,多用于处理高并发网络请求方面的问题。
此处使用的是Python 3.5之后出现的async/await来实现协程
基础补充(比较基础的内容懂的可以直接跳)
- 普通函数
def function(): return 1
2.由async做前缀的普通函数变成了异步函数
async def asynchronous():
return 1
而异步函数不同于普通函数不可能被直接调用
async def asynchronous():
return 1
print(asynchronous())
尝试用send驱动这个协程
async def asynchronous():
return 1
asynchronous().send(None)
值有了不过存储在了这个StopIteration报错中,于是有了下方的执行器
# -*- coding: utf-8 -*-
# @Time : 2022/11/22 16:03
# @Author : 红后
# @Email : not_enabled@163.com
# @blog : https://www.cnblogs.com/Red-Sun
# @File : async_function.py
# @Software: PyCharm
async def asynchronous():
return 1
def run(async_function): # 用try解决报错问题,运行协程函数
try:
async_function().send(None)
except StopIteration as r:
return r.value
print(run(asynchronous))
成功执行(`・ω・´)ゞ(`・ω・´)ゞ
在协程函数中await的使用(PS:await只能使用在有async修饰的函数中不然会报错)
await的作用是挂起自身的协程,直到await修饰的协程完成并返回结果(可参照第一点什么是协程中的描述)
# -*- coding: utf-8 -*-
# @Time : 2022/11/22 16:03
# @Author : 红后
# @Email : not_enabled@163.com
# @blog : https://www.cnblogs.com/Red-Sun
# @File : await_function.py
# @Software: PyCharm
async def asynchronous():
return 1
async def await_function(): # await挂起自身函数,等待另外协程函数运行完毕
result = await asynchronous()
return result
def run(async_function): # 用try解决报错问题,运行协程函数
try:
async_function().send(None)
except StopIteration as r:
return r.value
print(run(await_function))