在 Python 异步编程中使用 `awaitable` 对象

在 Python 异步编程中使用 awaitable 对象

awaitable 对象上,我们可以应用 await 语句。asyncio 中的大部分函数和模块被设计为可以与 awaitable 对象一起使用。但是大部分 Python 对象和第三方库,不是为异步编程构建的。当构建异步应用程序时,有一点非常重要,那就是选择提供可用 awaitble 对象的兼容库。

awaitalbe 对象主要被分成三种类型:协程、任务和期物 (Futures)。我们已经讨论过了协程和任务。期物是一种低层次对象,像一种回调机制,用来处理来自于async/await的结果。期物对象通常不会暴露于用户级编程。

并发运行任务

如果我们一定要并行运行多个任务,我们可以使用 await 关键字,就像我们在之前的例子中做的那样。但是有一种更好的方法做这件事,就是使用 gather 函数。这个函数会按提供的序列运行 awaitable 对象。如果任何awaitable 对象是协程,它将被调度为任务。后面的例子中我们会演示 gather 函数的使用。

使用队列分发任务

asyncio 包中的 Queue 队列和 Queue 模块类似,但是不是线程安全的。但是 asyncio 模块提供了多种队列实现,比如 FIFO 队列、优先级队列和LIFO队列。asyncio 模块中的队列可以用来把工作负载发布为任务。

为了演示任务对列的使用,我们会写一个小程序,通过随机休眠一段时间来模拟实际函数的执行时间。为 10 次这样的执行计算随机休眠时间,并且由主进程作为工作项添加到 Queue 对象中。Queue 队列被传递到一个有三个任务的池中。任务池中的每一个任务执行给定的协程,协程会消费每一个对它可见的队列记录中的执行时间(该协程根据其可用的队列条目消耗执行时间)。下面是完整的代码示例:

import time

async def executer(name, queue):
    while True:
        exec_time = await queue.get()
        await asyncio.sleep(exec_time)
        queue.task_done()

async def main():
    myqueue = asyncio.Queue()
    calc_execution_time = 0
    for _ in range(10):
        sleep_for = random.uniform(0.4, 0.8)
        calc_execution_time += sleep_for
        myqueue.put_nowait(sleep_for)

    tasks = []
    for id in range(3):
        task = asyncio.create_task(executer(f'任务-{id + 1}', myqueue))
        tasks.append(task)

    start_time = time.monotonic()
    await myqueue.join()
    total_exec_time = time.monotonic() - start_time

    for task in tasks:
        task.cancel()

    await asyncio.gather(*tasks, return_exceptions=True)

    print(f"执行时间:{calc_execution_time:0.2f}")
    print(f"实际执行时间:{total_exec_time:0.2f}")


asyncio.run(main())

我们使用 Queue 队列的 put_nowait 函数,因为它是一个非阻塞操作。上面的代码的执行结果是:

执行时间:6.22
实际执行时间:2.40

这清晰的演示了任务是并行执行的,执行时间是顺序执行的近三分之一。

<完>

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dowhileprogramming

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值