基于 async 和 await 关键字的协程可以实现异步编程,这也是目前 Python 异步相关的主流技术。在这里我们主要介绍一下实现异步的模块:asyncio 模块。
asyncio 模块是 Python 中实现异步的一个模块,该模块在 Python3.4 的时候发布,async 和 await 关键字在 Python3.5 中引入。因此,想要使用asyncio模块,建议 Python 解释器的版本不要低于 Python3.5 。
| 所谓的事件循环,我们可以把它当作是一个 while 循环,这个 while 循环在循环生命周期内运行并执行一些任务,在特定的条件下结束循环。 |
| 在编写程序的时候可以通过如下代码来获取和创建事件循环: |
| import asyncio |
| |
| loop = asyncio.get_event_loop() |
首先我们来看一下 *协程函数* ,什么是协程函数呢?直白的讲,定义为如下形式的函数,我们可以称之为协程函数,如下代码所示:
知道了什么是协程函数,接下来我们再来看一下什么是协程对象,所谓的协程对象就是调用协程函数之后返回的对象,我们称之为 *协程对象* ,如下代码所示:
注意事项:调用协程函数时,函数内部的代码不会执行,只是会返回一个协程对象!
在编写程序的时候,如果想要执行协程函数内部的代码,通过 \函数名()*** 调用函数是不可以的,需要 *事件循环* 和 *协程对象**** 配合才能实现,如下代码所示:
| import asyncio |
| |
| async def fn(): |
| print('协程函数内部的代码') |
| |
| def main(): |
| |
| res = fn() |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| asyncio.run(res) |
| |
| if __name__ == '__main__': |
| main() |
这个过程可以简单理解为:将 \协程函数*** 当做任务添加到 *事件循环* 的任务列表,然后事件循环检测列表中的*协程函数**** 是否已准备就绪(默认可理解为就绪状态),如果准备就绪则执行其内部代码。
| await 是一个 只能 在协程函数中使用的关键字,用于当协程函数遇到IO操作的时候挂起当前协程(任务),当前协程挂起过程中,事件循环可以去执行其他的协程(任务),当前协程IO处理完成时,可以再次切换回来执行 await 之后的代码,怎么理解呢?请看如下代码: |
*实例1*
| import asyncio |
| |
| async def fn(): |
| print('协程函数内部的代码') |
| |
| |
| |
| response = await asyncio.sleep(2) |
| |
| print(f'IO请求结束,结果为:{response}') |
| |
| def main(): |
| |
| res = fn() |
| |
| |
| asyncio.run(res) |
| |
| if __name__ == '__main__': |
| main() |
| |
| ''' |
| 运行结果: |
| 协程函数内部的代码 |
| IO请求结束,结果为:None |
| ''' |
*实例2*
| import asyncio |
| |
| async def other_tasks(): |
| print('start') |
| await asyncio.sleep(2) |
| print('end') |
| return '返回值' |
| |
| async def fn(): |
| print('协程函数内部的代码') |
| |
| |
| |
| response = await other_tasks() |
| |
| print(f'IO请求结束,结果为:{response}') |
| |
| def main(): |
| |
| res = fn() |
| |
| |
| asyncio.run(res) |
| |
| if __name__ == '__main__': |
| main() |
| |
| ''' |
| 运行结果: |
| 协程函数内部的代码 |
| start |
| end |
| IO请求结束,结果为:返回值 |
| ''' |
*实例3*
| import asyncio |
| |
| async def other_tasks(): |
| print('start') |
| await asyncio.sleep(2) |
| print('end') |
| return '返回值' |
| |
| async def fn(): |
| print('协程函数内部的代码') |
| |
| |
| |
| respnse1 = await other_tasks() |
| print(f'IO请求结束,结果为:{respnse1}') |
| |
| respnse2 = await other_tasks() |
| print(f'IO请求结束,结果为:{respnse2}') |
| |
| def main(): |
| |
| cor_obj = fn() |
| |
| |
| asyncio.run(cor_obj) |
| |
| if __name__ == '__main__': |
| main() |
| |
| ''' |
| 运行结果: |
| 协程函数内部的代码 |
| start |
| end |
| IO请求结束,结果为:返回值 |
| start |
| end |
| IO请求结束,结果为:返回值 |
| ''' |
上述的所有实例都只是创建了一个任务,即:事件循环的任务列表中只有一个任务,所以在IO等待时无法演示切换到其他任务效果。
在程序中想要创建多个任务对象,需要使用Task对象来实现。
| Tasks 用于并发调度协程,通过 asyncio.create_task(协程对象) 的方式创建 Task 对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task() 函数以外,还可以用低层级的loop.create_task() 或 ensure_future() 函数。并且不建议手动实例化 Task 对象。 |
| 本质上是将协程对象封装成 Task 对象,并将协程立即加入事件循环,同时追踪协程的状态。 |
| 注意事项:asyncio.create_task() 函数在 Python3.7 中被加入。在 Python3.7 之前,可以改用低层级的 asyncio.ensure_future() 函数。 |
*实例1*
| import asyncio |
| |
| async def other_tasks(): |
| print('start') |
| await asyncio.sleep(2) |
| print('end') |
| return '返回值' |
| |
| async def fn(): |
| print('fn开始') |
| |
| |
| task1 = asyncio.create_task(other_tasks()) |
| |
| |
| task2 = asyncio.create_task(other_tasks()) |
| |
| print('fn结束') |
| |
| |
| |
| response1 = await task1 |
| response2 = await task2 |
| print(response1, response2) |
| |
| def main(): |
| asyncio.run(fn()) |
| |
| if __name__ == '__main__': |
| main() |
| |
| ''' |
| 运行结果: |
| fn开始 |
| fn结束 |
| start |
| start |
| end |
| end |
| 返回值 返回值 |
| ''' |
*实例2*
| import asyncio |
| |
| async def other_tasks(): |
| print('start') |
| await asyncio.sleep(2) |
| print('end') |
| return '返回值' |
| |
| async def fn(): |
| print('fn开始') |
| |
| |
| task_lis = [ |
| asyncio.create_task(other_tasks()), |
| asyncio.create_task(other_tasks()), |
| ] |
| |
| print('fn结束') |
| |
| |
| |
| done, pending = await asyncio.wait(task_lis, timeout=None) |
| |
| print(done) |
| print(pending) |
| |
| def main(): |
| asyncio.run(fn()) |
| |
| if __name__ == '__main__': |
| main() |
| |
| ''' |
| 运行结果: |
| fn开始 |
| fn结束 |
| start |
| start |
| end |
| end |
| {<Task finished name='Task-3' coro=<other_tasks() done, defined at /Users/liumingyang/PycharmProjects/async_test/test.py:4> result='返回值'>, <Task finished name='Task-2' coro=<other_tasks() done, defined at /Users/liumingyang/PycharmProjects/async_test/test.py:4> result='返回值'>} |
| set() |
| ''' |