python - 将小函数转换为协程
问题描述
我觉得我对异步 IO 的理解存在差距:在更大的协程范围内将小函数包装到协程中是否有好处? 正确地发出事件循环的信号是否有好处?这种好处的程度是否取决于包装的函数是 IO 还是 CPU 绑定的?
示例:我有一个协程,download()
,它:
- 通过 . 从 HTTP 端点下载 JSON 序列化字节
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()
IO 绑定可能比 CPU 绑定更多。)
那么,这种类型的样板文件通常有什么好处吗?
async def compress(*args, **kwargs):
return bz2.compress(*args, **kwargs)
(现在comp = await compress(raw)
在download()
.)
哇啦,这现在是一个可等待的协程,因为一个单一return
的在原生协程中是有效的。有没有理由使用它?
根据这个答案,我听说过asyncio.sleep(0)
以类似方式随机投入的理由 - 只是为了单一备份到调用协程想要中断的事件循环。这是正确的吗?
解决方案
那么,这种类型的样板文件通常有什么好处吗?
async def compress(*args, **kwargs):
return bz2.compress(*args, **kwargs)
对它没有任何好处。与预期相反,添加 anawait
并不能保证控件将传递给事件循环 - 只有在等待的协程实际挂起时才会发生。由于compress
不等待任何东西,它永远不会挂起,所以它只是名义上的协程。
注意加入await asyncio.sleep(0)
协程并不能解决问题;有关更详细的讨论,请参见此答案。如果您需要运行阻塞功能,请使用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))
推荐阅读
- reactjs - 如何从另一个 React / ReactNative 组件触发 GraphQL 查询
- c# - 应用程序:应用程序启动器,无法移动目录,它正被另一个进程使用
- reactjs - 有什么方法可以防止用户在浏览器中通过 document.cookie 修改 cookie?
- angular - Angular 2 创建状态页面并在没有哈希的情况下访问
- python - 使用 Python 解析 JSON 中的 unicode 字符
- java - 如果找不到@Named,则使用匕首的默认实现
- python - 将请求 response.content 放入队列后,multiprocessing.Process 不会终止
- python - `TFRecord` 从 Google BigQuery 转储到 Google Cloud Storage
- java - JAVA GUI - 如何使用布局管理器重现我的 GUI?
- r - 聚合每个观察是否可以属于多个组