Kub*_*ski 11 asynchronous wrapper python-3.x python-requests python-asyncio
是一个函数,如:
async def f(x):
time.sleep(x)
await f(5)
Run Code Online (Sandbox Code Playgroud)
正确异步/非阻塞?
asyncio 提供的睡眠功能有什么不同吗?
最后,aiorequests 是请求的可行异步替代品吗?
(在我看来,它基本上将主要组件包装为异步)
https://github.com/pohmelie/aiorequests/blob/master/aiorequests.py
use*_*342 15
提供的函数不是正确编写的异步函数,因为它调用了asyncio 中禁止的阻塞调用。(“协程”有问题的一个快速提示是它不包含单个await。)被禁止的原因是诸如此类的阻塞调用sleep()将暂停当前线程而不给其他协程机会运行. 换句话说,不是暂停当前协程,而是暂停整个事件循环,即所有协程。
在 asyncio(和其他异步框架)中,阻塞原语之类的time.sleep()被替换为 awaitables 之类的asyncio.sleep(),它们暂停等待者并在适当的时候恢复它。其他协程和事件循环不仅不受协程挂起的影响,而且正是它们有机会运行的时候。协程的暂停和恢复是 async-await 协同多任务的核心。
Asyncio 支持在单独的线程中运行遗留阻塞函数,因此它们不会阻塞事件循环。这是通过调用run_in_executorwhich 将执行移交给线程池(Python模块的说法中的executorconcurrent.futures)并返回 asyncio awaitable 来实现的:
async def f(x):
loop = asyncio.get_event_loop()
# start time.sleep(x) in a separate thread, suspend
# the current coroutine, and resume when it's done
await loop.run_in_executor(time.sleep, x)
Run Code Online (Sandbox Code Playgroud)
这是 aiorequests 用来包装请求的阻塞函数的技术。原生 asyncio 函数asyncio.sleep() 不使用这种方法;它们直接告诉事件循环挂起它们以及如何唤醒它们(来源)。
run_in_executor对于快速包装遗留阻塞代码非常有用和有效,除此之外别无他法。由于以下几个原因,它始终不如本地异步实现:
它不实现取消。与线程不同,asyncio 任务是完全可取消的,但这并没有扩展到run_in_executor,它具有线程的局限性。
它不提供可能数以万计并并行运行的轻量级任务。run_in_executor在引擎盖下使用线程池,因此如果您等待的函数超过最大工作线程数,则某些函数将不得不等待轮到它们甚至开始工作。另一种方法是增加工作线程的数量,这将使操作系统淹没在过多线程中。Asyncio 允许并行操作的数量与您在手写状态机中poll用于侦听事件的数量相匹配。
它可能与更复杂的 API 不兼容,例如那些公开用户提供的回调、迭代器或提供自己的基于线程的异步功能的 API。
建议避免像 aiorequests 这样的拐杖,直接进入aiohttp。API 与请求的 API 非常相似,使用起来也几乎一样愉快。
| 归档时间: |
|
| 查看次数: |
3295 次 |
| 最近记录: |