python - 将小函数转换为协程

标签 python python-3.x python-asyncio

我觉得我对异步 IO 的理解存在差距:在较大的协程范围内将小函数包装到协程中有好处吗?这在信号方面有好处吗事件循环正确吗?这种好处的程度是否取决于包装函数是 IO 还是 CPU 绑定(bind)?

示例:我有一个协程 download(),它:

  1. 通过 aiohttp 从 HTTP 端点下载 JSON 序列化字节。
  2. 通过 bz2.compress() 压缩这些字节- 本身不可等待
  3. 通过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() 可能比 CPU 更受 IO 限制。)

那么,这种样板通常有什么好处吗?

async def compress(*args, **kwargs):
    return bz2.compress(*args, **kwargs)

(现在 comp = await compress(raw)download() 中。)

Wa-la,这现在是一个可等待的协程,因为唯一的 return 在原生协程中是有效的。是否有理由使用它?

根据 this answer ,我听说过以类似的方式随机放入 asyncio.sleep(0) 的理由 - 只是为了返回到调用协程想要中断的事件循环。这样对吗?

最佳答案

So, is there generally any benefit to this type of boilerplate?

async def compress(*args, **kwargs):
    return bz2.compress(*args, **kwargs)

它没有任何好处。出乎意料,添加了一个await doesn't guarantee控制将被传递到事件循环——只有当等待的协程实际挂起时才会发生。由于 compress 不会等待任何东西,它永远不会挂起,所以它只是名义上的协程。

请注意,在协程中添加await asyncio.sleep(0) 并不能解决问题;见this answer进行更详细的讨论。如果需要运行阻塞函数,请使用 run_in_executor :

async def compress(*args, **kwargs):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, lambda: bz2.compress(*args, **kwargs))

关于python - 将小函数转换为协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55857581/

相关文章:

python - 如何将图像加载到 python 3.4 tkinter 窗口中?

python - Discord.py 中的异步 REST API

python - 使用信号量限制并发 AsyncIO 任务数量不起作用

python - 删除小部件(涉及tkinter模块)

python - Django 的管理命令如何管理事务?

python-3.x - 标准化 Pandas 数据框但跳过几列

Python - Tkinter 中的 Matplotlib : The toolbar pan and zoom doesnt change the cursor

python - 使用 aiohttp 检测 http 响应编码

python - 在嵌套循环中查找 max 的最小索引,键严格位于第 0 个索引

python - 如何使用 NOAA API 查询给定坐标集的过去天气数据