Я разрабатываю библиотеку, которая должна поддерживать синхронизацию и асинхронность пользователей, сводя при этом к минимуму дублирование кода внутри библиотеки. Идеальным вариантом была бы реализация асинхронной библиотеки (поскольку библиотека выполняет удаленные вызовы API) и добавление поддержки синхронизации с помощью оболочки или что-то в этом роде. Рассмотрим следующую функцию как часть библиотеки.
Код: Выделить всё
# Library code
async def internal_function():
"""Internal part of my library doing HTTP call"""
pass
Код: Выделить всё
# Library code
def api_call():
"""Public api of my library"""
if asyncio.get_event_loop().is_running():
# Async caller
return internal_function() # This returns a coroutine, so the caller needs to await it
# Sync caller, so we need to run the coroutine in a blocking way
return asyncio.run(internal_function())
- users that call the function from an async function,
- users that call the function from a notebook (that's also async), and
- users that call the function from a plain python script (here it falls back to the blocking ).
Код: Выделить всё
asyncio.run
Код: Выделить всё
# Code from users of the library
async def entrypoint():
"""This entrypoint is called in an event loop, e.g. within fastlib"""
return legacy_sync_code() # Call to sync function
def legacy_sync_code():
"""Legacy code that does not support async"""
# Call to library code from sync function,
# expect value not coroutine, could not use await
api_response = api_call()
return api_response.json() # Needs to be value, not coroutine
Код: Выделить всё
json()
Код: Выделить всё
api_call()
In order to support these kind of users, I would need to
- identify if the direct calling function is sync and expects a value instead of a corouting,
- have a way to await the result of in a blocking way. Using
Код: Выделить всё
internal_function()
does only work in plain python scripts and fails if the code was called form an event loop higher up in the stack trace.Код: Выделить всё
asyncio.run
Код: Выделить всё
api_call_async()
Код: Выделить всё
api_call_sync()
I hope I make my point clear enough. I don't see way this should be fundamentally impossible, however, I can accept if the design of Python does not allow me to support sync and async users in a completely transparent way.
Источник: https://stackoverflow.com/questions/781 ... ync-client