Я чувствую, что в моем понимании асинхронного ввода-вывода есть пробел: Есть ли польза от преобразования небольших функций в сопрограммы в рамках больших сопрограмм? Есть ли польза для этого в сигнализациицикл событий правильно?Зависит ли степень этого преимущества от того, является ли обернутая функция IO или связанной с ЦП?
Пример: у меня есть сопрограмма, download()
, которая:
- Загрузки JSON-сериализованные байты из конечной точки HTTP через
aiohttp
. - Сжимает эти байты с помощью
bz2.compress()
- что само по себе не ожидаемо - Записываетсжатые байты в S3 через
aioboto3
Так что части 1 и 3 используют предопределенные сопрограммы из этих библиотек;часть 2 не по умолчанию.
Приведенный пример:
import bz2
import io
import aiohttp
import aioboto3
async def download(endpoint, bucket_name, key):
async with aiohttp.ClientSession() as session:
async with session.request("GET", endpoint, raise_for_status=True) as resp:
raw = await resp.read() # payload (bytes)
# Yikes - isn't it bad to throw a synchronous call into the middle
# of a coroutine?
comp = bz2.compress(raw)
async with (
aioboto3.session.Session()
.resource('s3')
.Bucket(bucket_name)
) as bucket:
await bucket.upload_fileobj(io.BytesIO(comp), key)
Как указывалось в комментарии выше, я всегда понимал, что добавление синхронной функции, такой как bz2.compress()
, всопрограмма может связываться с этим.(Даже если bz2.compress()
, вероятно, в большей степени связан с вводом-выводом, чем с процессором.)
Итак, есть ли вообще какая-то польза для этого типа шаблонов?
async def compress(*args, **kwargs):
return bz2.compress(*args, **kwargs)
(А теперь comp = await compress(raw)
в download()
.)
Ва-ля, теперь это ожидаемая сопрограмма, потому что подошва return
действительна в нативной сопрограмме.Есть ли основания для использования этого?
За этот ответ , я слышал оправдание для случайного добавления asyncio.sleep(0)
подобным образом - просто для однократного возврата доцикл обработки событий, в котором вызывающая сопрограмма хочет перерыв.Это правильно?