asyncio.run_in_executor定义存歧义?能否依赖其行为及修改接口合理性?
首先给你吃个定心丸:你完全可以安全依赖当前run_in_executor调用后立即提交任务的行为,下面我来拆解具体原因,以及解答你关于接口修改的疑问。
为什么可以依赖当前行为?
你的核心担忧是如果run_in_executor是协程,会等到await时才调度任务,但从以下几个维度来看,这个担忧是不必要的:
设计意图与实际行为匹配:
run_in_executor的核心作用是把同步阻塞的函数放到线程池/进程池里异步执行,设计上就要求调用时立即提交任务——如果要等到await才调度,那它和直接在协程里调用同步函数没有本质区别,完全违背了异步IO的初衷。Python官方不会做出这种颠覆接口核心功能的变更。文档与PEP的核心指向:
虽然文档对“awaitable”的表述有点模糊,但明确说明它返回asyncio.Future。而Future对象的特性是:当它被创建并关联任务后,任务就已经进入调度队列了(这里run_in_executor在返回Future前就已经把work提交给executor了)。另外PEP 3156没有将run_in_executor定义为协程,说明这个接口的核心是返回可等待对象,而非自身作为协程。社区讨论与实现细节的边界:
你提到的issue(25675、32327)里,虽然把“run_in_executor是返回awaitable的函数还是协程本身”视为实现细节,但任务提交的时机绝对不是实现细节。如果这个行为变更,会破坏大量现有依赖异步调度的代码,Python官方在做这类变更时会极其谨慎,甚至不会做这种不兼容的修改。
将AbstractEventLoop.run_in_executor改为普通函数是否合理?
从实际使用、实现现状和社区反馈来看,这个修改是合理的:
- 当前
BaseEventLoop的实现已经是普通函数,接口定义为协程反而造成了混淆,让开发者误以为它需要被await才会执行核心逻辑。 - 从接口职责来看,
run_in_executor的逻辑是同步的:它只是把任务提交给executor,然后返回Future,本身没有异步操作需要等待,完全符合普通函数的定位。 - 社区里也有不少开发者提出过类似的疑问,认为这个接口定义为协程是个设计瑕疵,改成普通函数能减少误解,更贴合实际行为。
内容的提问来源于stack exchange,提问作者Chris Hunt

