1. ホーム
  2. python

[解決済み] Pythonで可能な最も単純なasync/awaitの例

2022-03-15 12:10:29

質問

に関する多くの事例、ブログ記事、質問/回答を読みました。 asyncio / async / await Python 3.5+ では、多くは複雑でしたが、私が見つけた最もシンプルなものは、おそらく これ .
それでも ensure_future Pythonの非同期プログラミングの学習用として、さらに最小限の例を見てみたいと思います。 必要最小限のツール 基本的な async / await の例を行うために。

質問: を示す簡単な例です。 async / await 作品 この2つのキーワード+非同期ループを実行するコード+他の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:非同期/待ち合わせを間違えた場合

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: 非同期/待ちを正しく行う場合

を除いて、ケース2と同じです。 sleep 関数を使用します。

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秒 . そのため 非同期/待機が正しく行われる の方が速い。

この差の理由は 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)

この記事の詳細 こちら

更新日:2020年5月02日

読み方を考える