mirror of
https://github.com/Estom/notes.git
synced 2026-02-03 02:23:31 +08:00
asyncio
This commit is contained in:
@@ -143,3 +143,122 @@ await asyncio.wait([a(), b()])
|
||||
```
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## 最贱实践
|
||||
|
||||
> 一个比较好的实践
|
||||
|
||||
### 总结
|
||||
|
||||
1. async只是声明了一个函数是可异步的。
|
||||
2. await关键字是核心,所有的await点可以共同调度。await关键字是核心,所有的await点可以共同调度。await 调用相当于 协程调度的切入点。只有async函数可以被await调用。
|
||||
3. 本质上是select/epoll机制与java asyncio一样,都是将多个io操作阻塞在同一个进程上,通过事件响应处理。
|
||||
4. asyncio.gather() asyncio.run()用于启动多协程。所以异步函数必须有统一的入口。这两个函数是并发的启动点。如果asyncio 只run了一个async函数(即协程)则不存在并发。所以一般都是跟循环结合起来进行并发。
|
||||
5. 异步只有用在io操作上才有意义。async函数表示其内部的执行过程中存在io操作。await调用表示允许在调用过程中终端执行。所以**调用的起点**必然是asyncio.run()运行一组协程(运行时已经决定了启动的协程的数量)。**调用的终点**必然是一个可以await的io操作。在示例程序中一般是asyncio.sleep()模拟一个可以await的io操作
|
||||
6. 一个优势是避免了回调函数。那我们来拆分下,回调函数包括几部分:回调前的同步操作,执行IO操作(可以异步并发),IO操作后执行回调函数(可以异步并发)。那么async await关键字是如何避免回调函数呢?使用await调用前的部分,可以理解为IO操作前的同步操作。使用await完成了一个比较耗时的IO操作。await之后的代码,则相当于回调函数的部分。用于在IO操作完成时进行回调。与直接调用相比,就是await调用执行了一个 IO操作,并且运行在这个点上进行并发调度。
|
||||
|
||||
### 有哪些方式可以实现并发
|
||||
|
||||
Python 中执行一个 async 函数(异步函数或协程函数)通常使用以下方法:
|
||||
|
||||
1. asyncio.run: 是 Python 3.7 新增加的高级 API,用于运行最高级别的异步函数入口点。
|
||||
```
|
||||
import asyncio
|
||||
|
||||
async def async_function():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
# 运行异步函数
|
||||
asyncio.run(async_function())
|
||||
```
|
||||
2. event_loop.run_until_complete: 这是在 asyncio.run 出现之前的传统方式,你需要手动获取事件循环,然后在事件循环中运行协程。
|
||||
```
|
||||
import asyncio
|
||||
|
||||
async def async_function():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
# 获取当前事件循环
|
||||
loop = asyncio.get_event_loop()
|
||||
# 在事件循环中执行异步函数
|
||||
loop.run_until_complete(async_function())
|
||||
# 关闭事件循环(在使用完后需要关闭,尤其在生产环境中)
|
||||
loop.close()
|
||||
```
|
||||
|
||||
3. asyncio.create_task 或 asyncio.ensure_future: 这些函数可以把一个异步函数封装成一个任务(task),这个任务会被安排在事件循环中运行。
|
||||
```
|
||||
import asyncio
|
||||
|
||||
async def async_function():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
async def main():
|
||||
task = asyncio.create_task(async_function()) # Python 3.7+
|
||||
# task = asyncio.ensure_future(async_function()) # 兼容性更强的方法
|
||||
await task
|
||||
|
||||
asyncio.run(main())
|
||||
在异步上下文中使用 await: 可以在一个异步函数内部使用 await 来运行其他的异步函数。
|
||||
import asyncio
|
||||
|
||||
async def async_function():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
async def main():
|
||||
# 在此调用异步函数
|
||||
await async_function()
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
|
||||
4. 并发运行多个异步函数(使用 async.gather 或 asyncio.wait 等): 当你想同时运行多个异步任务时,可以使用 asyncio.gather() 或 asyncio.wait()。
|
||||
```
|
||||
import asyncio
|
||||
|
||||
async def async_function_one():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
async def async_function_two():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
async def main():
|
||||
# 同时运行两个异步函数
|
||||
await asyncio.gather(
|
||||
async_function_one(),
|
||||
async_function_two(),
|
||||
)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
5. 使用异步上下文管理器(async with): 如果需要自动管理资源(如打开和关闭连接),可以在 async with 语句中运行异步函数。
|
||||
```
|
||||
import asyncio
|
||||
|
||||
class AsyncContextManager:
|
||||
async def __aenter__(self):
|
||||
# 设置资源
|
||||
pass
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
# 清理资源
|
||||
pass
|
||||
|
||||
async def async_function():
|
||||
# 异步操作
|
||||
pass
|
||||
|
||||
async def main():
|
||||
async with AsyncContextManager(): # 可以省略 as var,如果不需要变量的话
|
||||
await async_function()
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
请注意,asyncio.run() 实际上是一个方便的函数,它创建了一个新的事件循环,运行传递给它的协程,然后关闭事件循环。但是,如果你已经在一个异步环境中(比如已经运行在一个事件循环内),你就不能再次使用 asyncio.run()。在那种情况下,你需要使用 await,配合 asyncio.create_task() 或者直接等待异步函数。
|
||||
Reference in New Issue
Block a user