Я не могу использовать asyncio.run (), потому что у вызывающей стороны уже может быть запущено событие l oop, и вы можете иметь только один l oop на поток.
Если у вызывающего абонента есть запущенное событие l oop, вы не должны запускать блокирующий код в первую очередь, потому что это заблокирует вызывающего абонента l oop!
С учетом этого, ваш лучший вариант действительно должен do_things
asyn c и вызывать код syn c с использованием run_in_executor
, который предназначен именно для этого случая использования:
async def do_things():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, sync_stuff)
await async_func()
await loop.run_in_executor(None, more_sync_stuff)
Эта версия do_things
может использоваться из asyn c код как await do_things()
и из syn c код как asyncio.run(do_things())
.
Сказав это ... если вы знаете, что код syn c будет работать очень быстро, или вы по какой-то причине, желая заблокировать событие вызывающего абонента l oop, вы можете обойти ограничение, запустив событие l oop в отдельном потоке:
def run_async(aw):
result = None
async def run_and_store_result():
nonlocal result
result = await aw
t = threading.Thread(target=asyncio.run, args=(run_and_store_result(),))
t.start()
t.join()
return result
do_things
может выглядеть так :
async def do_things():
sync_stuff()
run_async(async_func())
more_sync_stuff()
Будет вызываться из кода syn c и асин c, но стоимость будет такой: * 10 24 *
- это создаст совершенно новое событие l oop каждый раз. (Хотя вы можете кэшировать событие l oop и никогда не выходить из него.)
- при вызове из асинхронного кода c, оно заблокирует событие вызывающего абонента l oop, таким образом, эффективно нарушая его асинхронное использование, даже если большая часть времени фактически проводится внутри собственного асин c кода.