web-dev-qa-db-ja.com

python asyncio add_done_callback with async def

2つの関数があります。最初の関数はdef_aが非同期関数で、2番目の関数がdef_bです。これは通常の関数であり、def_aの結果でコールバックとして呼び出されます。 add_done_callback関数。

私のコードは次のようになります:

import asyncio

def def_b(result):
    next_number = result.result()
    # some work on the next_number
    print(next_number + 1)

async def def_a(number):
    await some_async_work(number)
    return number + 1

loop = asyncio.get_event_loop()
task = asyncio.ensure_future(def_a(1))
task.add_done_callback(def_b)
response = loop.run_until_complete(task)
loop.close()

そしてそれは完璧に機能します。

問題は、2番目の関数def_bも非同期になったときに始まりました。これは次のようになります。

async def def_b(result):
    next_number = result.result()
    # some asynchronous work on the next_number
    print(next_number + 1)

しかし、これはadd_done_callback関数に提供できません。これは、通常の関数ではないためです。

私の質問は-def_bが非同期の場合、add_done_callback関数にdef_bを提供することは可能ですか?

13
Yuval Pruss

_add_done_callback_は「低レベル」インターフェースと見なされます。コルーチンを操作する場合、次のように、さまざまな方法で それらをチェーン できます。

_import asyncio


async def my_callback(result):
    print("my_callback got:", result)
    return "My return value is ignored"


async def coro(number):
    await asyncio.sleep(number)
    return number + 1


async def add_success_callback(fut, callback):
    result = await fut
    await callback(result)
    return result


loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coro(1))
task = add_success_callback(task, my_callback)
response = loop.run_until_complete(task)
print("response:", response)
loop.close()
_

将来、例外が発生した場合でも、_add_done_callback_はコールバックを呼び出します(ただし、result.result()を呼び出すと、コールバックが発生します)。

20
Udi

これは1つの将来のジョブでのみ機能します。複数の非同期ジョブがある場合、それらは互いにブロックします。より良い方法は、asyncio.as_comleted()を使用して将来のリストを繰り返すことです。

import asyncio

async def __after_done_callback(future_result):
    # await for something...
    pass

async def __future_job(number):
    await some_async_work(number)
    return number + 1

loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(__future_job(x)) for x in range(100)]  # create 100 future jobs

for f in asyncio.as_completed(tasks):
    result = await f
    await __after_done_callback(result)

loop.close()
1
user3593261