【发布时间】:2019-09-15 09:01:11
【问题描述】:
我觉得我对异步 IO 的理解存在差距:在更大的协程范围内,将小函数包装到协程中是否有好处?这在发信号方面有好处吗?事件循环正确吗?这种好处的程度是否取决于被包装的函数是 IO 还是 CPU 密集型的?
示例:我有一个协程,download(),它:
- 通过
aiohttp从 HTTP 端点下载 JSON 序列化字节。 - 通过
bz2.compress()压缩这些字节 - 这本身不能等待 - 通过
aioboto3将压缩字节写入S3
所以第 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() 的 IO 绑定可能比 CPU 绑定更多。)
那么,这种类型的样板文件通常有什么好处吗?
async def compress(*args, **kwargs):
return bz2.compress(*args, **kwargs)
(现在comp = await compress(raw) 在download() 内。)
哇啦,这现在是一个可等待的协程,因为唯一的return 在本机协程中是有效的。有没有理由使用它?
根据this answer,我听说了以类似方式随机抛出asyncio.sleep(0) 的理由——只是为了单一备份到调用协程想要中断的事件循环。是这样吗?
【问题讨论】:
-
你关于小型协程的问题很有趣,但也许你会从运行同步函数中获得更多好处in executor?
-
有人可能会对此做出回答:只是将一个函数放在协程中并不会使其异步:它仍然会阻塞。正如@sanyash 所提到的,如果您在此期间还有其他事情要做,将它放在执行程序中将有助于在另一个线程中运行它。
标签: python python-3.x python-asyncio