Python asyncio add_done_callback с async def
У меня есть 2 функции: первая, def_a
, является асинхронной функцией, а вторая - 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()
И он отлично работает.
Проблема началась, когда вторая функция 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
является асинхронным?
Ответы
Ответ 1
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()
приведет к его повышению).
Ответ 2
Это работает только для одной будущей работы, если у вас есть несколько асинхронных заданий, они будут блокировать друг друга, лучше использовать 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()