#python-3.x #async-await #future
#python #python-3.x #async-await #python-asyncio #будущее
Вопрос:
Я пытаюсь понять python async / await и использую Future
объекты, чтобы указать, что функция может продолжаться. Это некоторый код, который воспроизводит проблему, с которой я столкнулся:
import time, threading, asyncio
loop = asyncio.get_event_loop()
f = loop.create_future()
def resolve(fut):
for i in range(3):
print(i)
time.sleep(1)
fut.set_result(88)
async def wait_on_future(fut):
print('waiting for fut')
await fut
print('done', fut.result())
return fut.result()
threading.Thread(target=resolve, args=(f,)).start()
loop.create_task(wait_on_future(f))
loop.run_forever()
который печатает:
0
waiting for fut
1
2
Обратите внимание, что он никогда не печатается 'done'
. В разделе ожидаемых документов говорится:
Когда ожидается объект Future, это означает, что сопрограмма будет ждать, пока будущее не будет разрешено в каком-либо другом месте.
Я думал, что вызов set_result
— это способ разрешить a Future
. Чего мне здесь не хватает?
Примечание: если я вызываю resolve в том же потоке, это работает нормально. Реальная проблема, которую я пытаюсь решить, заключается в том, что событие, которое происходит для разрешения Future
, находится в потоке. Я заметил, что в будущих документах говорится, что он не является потокобезопасным. Как создать асинхронную функцию, которая ожидает события, происходящего в другом потоке?
Комментарии:
1. «> Я заметил, что в будущих документах говорится, что это не потокобезопасно.» Большая часть asyncio не является потокобезопасной. Часто не имеет смысла использовать как asyncio, так и потоки. Вы пробовали вместо этого использовать многопроцессорную обработку?
2. @CharmingRobot Потоки происходят из кода C , обернутого cython. Я пытаюсь использовать обратные вызовы, запускаемые этими потоками, для разрешения фьючерсов в некотором асинхронном коде. Я знаком с многопроцессорной обработкой; это не помогает решить эту проблему, но спасибо за мысль.
3. Вы взглянули на функцию
run_in_executor
asyncio? может быть, вы можете вызвать `await run_in_executor(resolve (f)) из своей сопрограммы?4. Также, если вы хотите запланировать сопрограмму в другом потоке, вы можете использовать
asyncio.run_coroutine_threadsafe
. docs.python.org/3/library /…5. @CharmingRobot Я думаю
run_coroutine_threadsafe
, может сработать для меня, спасибо за ссылку!
Ответ №1:
Хорошо, благодаря комментарию @CharmingRobot о run_coroutine_threadsafe
том, что я пришел к этому решению:
import time, threading, asyncio
loop = asyncio.get_event_loop()
f = loop.create_future()
def resolve(fut):
for i in range(3):
print(i)
time.sleep(1)
async def a_resolve():
fut.set_result(88)
asyncio.run_coroutine_threadsafe(a_resolve(), loop)
async def wait_on_future(fut):
print('waiting for fut')
return await fut
async def print_future():
print('got the future! value:', await wait_on_future(f))
loop.create_task(print_future())
threading.Thread(target=resolve, args=(f,)).start()
loop.run_forever()
который печатает:
0
waiting for fut
1
2
got the future! value: 88
это то, что я искал.