web-dev-qa-db-ja.com

Asyncio.gatherとasyncio.wait

asyncio.gatherasyncio.wait は似たような使い方をしているようです。開始します。これらは異なる構文を使用しており、細部が若干異なりますが、機能的にこのように大きな重複がある2つの関数を持つことは私にとってはPythonicとは非常に異なるようです。何が足りないの?

90
Claude

一般的なケースでは似ていますが( "多くのタスクを実行して結果を得る")、各関数は他のケースでも特定の機能を持っています。

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()
115
Udi

asyncio.waitasyncio.gatherより低レベルです。

名前が示すように、asyncio.gatherは主に結果の収集に焦点を当てています。それはたくさんの未来を待ち、与えられた順番で結果を返します。

asyncio.waitは先物を待つだけです。そして直接あなたに結果を与えるのではなく、それは行われたそして保留中のタスクを与えます。あなたは手動で値を集める必要があります。

さらに、すべての先物が終了するのを待つように指定することも、最初のものだけをwaitで指定することもできます。

25
ospider

また、リストを指定するだけで、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)
    ))
10
Johny Ebanat