Asyncio.gatherとasyncio.wait


148

asyncio.gatherそして、asyncio.wait同様の用途を持っているように見える:私は(必ずしも次の開始前に終了するのを待っていない1)のために/待機を実行したいことを、私は非同期物事の束を持っています。それらは異なる構文を使用しており、一部の詳細は異なりますが、機能が非常に重複している2つの関数を使用することは、私には非常に不便です。何が欠けていますか?

回答:


177

一般的なケース(「実行して多くのタスクの結果を取得する」)は似ていますが、各関数には他の場合に特定の機能があります。

asyncio.gather()

タスクの高レベルのグループ化を可能にするFutureインスタンスを返します。

import asyncio
from pprint import pprint

import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(1, 3))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

group1 = asyncio.gather(*[coro("group 1.{}".format(i)) for i in range(1, 6)])
group2 = asyncio.gather(*[coro("group 2.{}".format(i)) for i in range(1, 4)])
group3 = asyncio.gather(*[coro("group 3.{}".format(i)) for i in range(1, 10)])

all_groups = asyncio.gather(group1, group2, group3)

results = loop.run_until_complete(all_groups)

loop.close()

pprint(results)

グループ内のすべてのタスクは、group2.cancel()またはを呼び出すことでキャンセルできますall_groups.cancel()。も参照してください.gather(..., return_exceptions=True)

asyncio.wait()

最初のタスクが完了した後、または指定されたタイムアウト後に停止の待機をサポートし、操作の低レベルの精度を可能にします。

import asyncio
import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(0.5, 5))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

tasks = [coro(i) for i in range(1, 11)]

print("Get first result:")
finished, unfinished = loop.run_until_complete(
    asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED))

for task in finished:
    print(task.result())
print("unfinished:", len(unfinished))

print("Get more results in 2 seconds:")
finished2, unfinished2 = loop.run_until_complete(
    asyncio.wait(unfinished, timeout=2))

for task in finished2:
    print(task.result())
print("unfinished2:", len(unfinished2))

print("Get all other results:")
finished3, unfinished3 = loop.run_until_complete(asyncio.wait(unfinished2))

for task in finished3:
    print(task.result())

loop.close()

4
「単一のアスタリスク形式(* args)はキーワードのない可変長引数リストを渡すために使用され、二重のアスタリスク形式はキーワード付きの可変長引数リストを渡すために使用されます」
laycat

40

asyncio.waitより低いレベルですasyncio.gather

名前が示すように、asyncio.gather主に結果の収集に焦点を当てています。たくさんの先物を待って、指定された順序で結果を返します。

asyncio.wait先物を待つだけです。結果を直接提供するのではなく、完了したタスクと保留中のタスクを提供します。手動で値を収集する必要があります。

さらに、すべての先物が完了するのを待つか、最初の先物だけを待つかを指定できますwait


あなたは言う:it waits on a bunch of futures and return their results in a given order。10000000000000タスクがあり、それらすべてが大きなデータを返す場合はどうなりますか?すべての結果はメモリブームになりますか?
キングネーム

@Kingname ..wat
Matt Joiner

12

また、リストを指定するだけで、wait()にコルーチンのグループを提供できることにも気付きました。

result=loop.run_until_complete(asyncio.wait([
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ]))

一方、gather()でのグループ化は、複数のコルーチンを指定するだけで行われます。

result=loop.run_until_complete(asyncio.gather(
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ))

20
リストでも使用することができgather()、例えば:asyncio.gather(*task_list)
tehfink

1
発電機もそう
Jab

スクリプトの残りをブロックせずに、このギャザーをどのように使用できますか?
thebeancounter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.