沙滩星空的博客沙滩星空的博客

python3异步和并发任务的实现

可等待对象

如果一个对象可以在 await 语句中使用,那么它就是 可等待 对象。许多 asyncio API 都被设计为接受可等待对象。

可等待 对象有三种主要类型: 协程, 任务 和 Future.

协程

协程 属于 可等待 对象,通过 async/await 语法进行声明,是编写 asyncio 应用的推荐方式。

协程函数: 定义形式为 async def 的函数;
协程对象: 调用 协程函数 所返回的对象。

注意:简单地调用一个协程函数并不会立即执行,只是返回一个协程对象
使用 asyncio.run() 函数来调用协程对象协程函数才会被真正执行。

示例1:

>>> import asyncio

>>> async def main():
...     print('hello')
...     await asyncio.sleep(1)
...     print('world')

>>> main()
<coroutine object main at 0x1053bb7c8>

>>> asyncio.run(main())
hello
world

示例2:

import asyncio

async def nested():
    return 42

async def main():
    # 此处仅仅创建了一个协程对象,nested函数并没有真正执行。
    # 必须使用 await 关键字,后面可用asyncio.run()函数调用执行。
    nested()

    # 使用 await 关键字
    print(await nested())  # will print "42".

main())

任务

任务 被用来设置日程以便 并发 执行协程。【个人理解:协程无法直接并发执行,必须打包成任务】

创建任务

asyncio.create_task(coro, *, name=None)

协程对象 coro 打包为一个 Task 任务,排入日程准备执行。 返回 Task 对象
name 不为 None,它将使用 Task.set_name() 来设为任务的名称。
该任务会在 get_running_loop() 返回的循环中执行,如果当前线程没有在运行的循环则会引发 RuntimeError。

休眠

coroutine asyncio.sleep(delay, result=None, *, loop=None)

并发运行任务

awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)

并发 运行 aws 序列中的 可等待对象.
如果 aws 中的某个可等待对象为协程,它将自动作为一个任务(自动创建Task对象)加入日程。
如果所有可等待对象都成功完成,结果将返回一个由所有返回值聚合而成的列表。

示例代码:

import asyncio
import time

# 并发执行协程
# 模拟的耗时任务 交给协程来处理
async def my_task(name, number):
    await asyncio.sleep(number)
    print('%s 已经完成任务...' % name)
    return number

async def main():
    print(f"started at {time.strftime('%X')}")

    # 将三个任务交给 asyncio.gather 并发执行。预期耗时4秒,否则未达到预期
    main_res = await asyncio.gather(
        my_task('A', 2),
        my_task('B', 3),
        my_task('C', 4),
    )
    
    # 压缩参数为列表变量的形式
    # task_list = [my_task('A', 2), my_task('B', 2), my_task('C', 4)]
    # main_res = await asyncio.gather(*task_list)

    # 以下方法为并发异步执行,可达相同预期。 但在协程较多时,推荐使用上法
    # task1 = asyncio.create_task(my_task('A', 2))
    # task2 = asyncio.create_task(my_task('B', 3))
    # task3 = asyncio.create_task(my_task('C', 4))
    # await task1
    # await task2
    # await task3

    # 返回一个由所有返回值聚合而成的列表
    print(main_res)

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

结果如下:

started at 14:46:26
A 已经完成任务...
B 已经完成任务...
C 已经完成任务...
[2, 3, 4]
finished at 14:46:30
  1. async def my_task(name, number) 为需要并发执行的异步方法.
  2. 通过 await asyncio.gather(),对多个并发执行的函数方法,进行调用。
  3. await asyncio.gather() 放入 async def main() 方法函数中使用。
  4. 使用 asyncio.run(main()) 调用 async def main() 方法

asyncio 异步 I/O https://docs.python.org/zh-cn/3.9/library/asyncio.html
简单粗暴有效上手Python3异步asyncio https://blog.csdn.net/lpwmm/article/details/102985040
Python3.7 高级编程之 async/await asyncio 通过任务gather并发运行协程 https://blog.csdn.net/haeasringnar/article/details/100181731

未经允许不得转载:沙滩星空的博客 » python3异步和并发任务的实现

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址