Ответ 1
Если сторонняя библиотека не совместима с async/await
, то, очевидно, вы не можете легко ее использовать. Есть два случая:
-
Скажем, что функция в библиотеке асинхронна и дает вам обратный вызов, например.
def fn(..., clb): ...
Итак, вы можете сделать:
def on_result(...): ... fn(..., on_result)
В этом случае вы можете обернуть такие функции в протокол asyncio следующим образом:
from asyncio import Future def wrapper(...): future = Future() def my_clb(...): future.set_result(xyz) fn(..., my_clb) return future
(используйте
future.set_exception(exc)
для исключения)Затем вы можете просто вызвать эту оболочку в некоторой функции
async
с помощьюawait
:value = await wrapper(...)
Обратите внимание, что
await
работает с любым объектомFuture
. Вам не нужно объявлятьwrapper
какasync
. -
Если функция в библиотеке синхронна, вы можете запустить ее в отдельном потоке (возможно, для этого вам понадобится некоторый пул потоков). Весь код может выглядеть так:
import asyncio import time from concurrent.futures import ThreadPoolExecutor # Initialize 10 threads THREAD_POOL = ThreadPoolExecutor(10) def synchronous_handler(param1, ...): # Do something synchronous time.sleep(2) return "foo" # Somewhere else async def main(): loop = asyncio.get_event_loop() futures = [ loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), ] await asyncio.wait(futures) for future in futures: print(future.result()) with THREAD_POOL: loop = asyncio.get_event_loop() loop.run_until_complete(main())
Если вы не можете использовать потоки по какой-либо причине, то использование такой библиотеки просто делает весь асинхронный код бессмысленным.
Обратите внимание, что использование синхронной библиотеки с async, вероятно, является плохим. Вы не получите много, и все же вы сильно усложняете код.