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

2023-11-26

我读过很多例子、博客文章、问题/答案asyncio / async / await在 Python 3.5+ 中,很多都很复杂,我发现的最简单的可能是this one.
仍然使用ensure_future,为了学习 Python 中的异步编程,我希望看到一个更简单的示例,以及什么是所需的最少工具做一个基本的异步/等待示例。

问题: 是否可以给一个简单的例子展示了如何async / await works,仅使用这两个关键字 + 运行异步循环的代码 + 其他 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,并且仍然演示了等待/异步是如何工作的。


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

情况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')

Output:

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')

Output:

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 正确完成

与情况 2 相同,除了sleep功能:

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

Output:

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秒。所以异步/等待正确完成是比较快的。

造成差异的原因是在实施过程中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 中,它们是“相同的”: 他们“睡觉”,不允许其他人使用资源。 而在情况 3 中,它允许在休眠时访问资源。

在案例 2 中,我们添加了async到正常功能。然而事件循环将运行它不间断。 为什么?因为我们没有说哪里允许循环中断你的函数来运行另一个任务。

在情况 3 中,我们准确地告诉事件循环在哪里中断函数以运行另一个任务。具体在哪里?就在这儿!

await asyncio.sleep(1)

有关这方面的更多信息,请阅读here.

考虑阅读

  • 异步编程搭车指南
  • Asyncio 期货和协程
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 中最简单的异步/等待示例 的相关文章