python - Python 中最简单的异步/等待示例

标签 python python-3.x asynchronous async-await python-asyncio

我已经阅读了很多关于 Python 3.5+ 中的 asyncio/async/await 的示例、博客文章、问题/答案,很多都是复杂,我发现最简单的可能是 this one .
它仍然使用 ensure_future,并且出于学习 Python 异步编程的目的,我希望看到一个更简单的示例,以及必要的最小工具是什么基本异步/等待示例。

问题:是否可以给出一个简单的例子来说明async/await 是如何工作的,只使用这两个关键字+代码来运行异步循环 + 其他 Python 代码但没有其他 asyncio 函数?

例子:像这样:

import asyncio

async def async_foo():
    print("async_foo started")
    await asyncio.sleep(5)
    print("async_foo done")

async def main():
    asyncio.ensure_future(async_foo())  # fire and forget async_foo()
    print('Do some actions 1')
    await asyncio.sleep(5)
    print('Do some actions 2')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

但没有 ensure_future,并且仍然演示 await/async 是如何工作的。

最佳答案

为了回答您的问题,我将针对同一问题提供 3 种不同的解决方案。

案例 1:只是普通的 Python

import time

def sleep():
    print(f'Time: {time.time() - start:.2f}')
    time.sleep(1)

def sum(name, numbers):
    total = 0
    for number in numbers:
        print(f'Task {name}: Computing {total}+{number}')
        sleep()
        total += number
    print(f'Task {name}: Sum = {total}\n')

start = time.time()
tasks = [
    sum("A", [1, 2]),
    sum("B", [1, 2, 3]),
]
end = time.time()
print(f'Time: {end-start:.2f} sec')

输出:

Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3

Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6

Time: 5.02 sec

案例 2:async/await 做错了

import asyncio
import time

async def sleep():
    print(f'Time: {time.time() - start:.2f}')
    time.sleep(1)

async def sum(name, numbers):
    total = 0
    for number in numbers:
        print(f'Task {name}: Computing {total}+{number}')
        await sleep()
        total += number
    print(f'Task {name}: Sum = {total}\n')

start = time.time()

loop = asyncio.get_event_loop()
tasks = [
    loop.create_task(sum("A", [1, 2])),
    loop.create_task(sum("B", [1, 2, 3])),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

end = time.time()
print(f'Time: {end-start:.2f} sec')

输出:

Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3

Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6

Time: 5.01 sec

案例 3:async/await 正确完成

除了 sleep 函数外,与情况 2 相同:

async def sleep():
    print(f'Time: {time.time() - start:.2f}')
    await asyncio.sleep(1)

输出:

Task A: Computing 0+1
Time: 0.00
Task B: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task B: Computing 1+2
Time: 1.00
Task A: Sum = 3

Task B: Computing 3+3
Time: 2.00
Task B: Sum = 6

Time: 3.01 sec

案例 1 和案例 2 给出了相同的 5 秒,而案例 3 只给出了 3 秒。因此,正确完成 async/await 速度更快。

差异的原因在于 sleep 函数的实现。

# case 1
def sleep():
    ...
    time.sleep(1)

# case 2
async def sleep():
    ...
    time.sleep(1)

# case 3
async def sleep():
    ...
    await asyncio.sleep(1)

在情况 1 和情况 2 中,它们是“相同的”: 他们在不允许其他人使用资源的情况下“ sleep ”。 而在情况 3 中,它允许在 sleep 时访问资源。

在案例 2 中,我们将 async 添加到普通函数中。然而,事件循环将不间断地运行。 为什么?因为我们没有说明允许循环在哪里中断您的函数以运行另一个任务。

在案例 3 中,我们告诉事件循环在何处中断函数以运行另一个任务。具体在哪里?就在这里!

await asyncio.sleep(1)

有关此阅读的更多信息 here

2020 年 5 月 2 日更新

考虑阅读

关于python - Python 中最简单的异步/等待示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50757497/

相关文章:

python - 如何在 python 中用一个变量替换 %s

python - 类型错误 : '<' not supported between instances - objects

python - 是否可以让装饰器在 asyncio 执行器中运行阻塞函数?

python - Flask - 提交按钮提交所有表单而不是一张表单

python - 代码有什么问题?结果在Google Kickstart 2020 Round A中产生RE

python - 返回嵌套字典中具有最大值的键的名称

python - 为什么 @property 中断了与代理类上的源对象的同步

python - 使用 pandas 包用 python 清理 excel 数据

javascript - 调用由 key 标识的异步函数

javascript - 如何在 jQuery 中链接延迟对象?