执行者何时(以及如何)将控制权交还给事件循环?

问题描述 投票:0回答:1

我第一次尝试全神贯注于

asyncio
,我想我已经对协同程序以及如何等待它们的相应对象有了基本的了解。现在,我遇到了
AbstractEventLoop.run_in_executor
,这个概念在抽象上是有意义的(没有双关语意):你有一些阻塞操作,所以你把它踢到一个线程,这样主线程(即运行主线程的线程事件循环)可以继续它的工作。

我不明白的是事件循环如何管理协程(协作多任务处理)和这个新创建的线程(抢占式多任务处理)之间的上下文切换。据我了解,每个协程都是

await
ed,并且
await
ing协程的行为将控制权交还给事件循环。这允许事件循环开始运行另一个协程。但是线程不是以这种方式协作的——还有一些其他调度程序(我相信你的操作系统,但这可能是错误的)调度线程何时运行,并且线程可以在它们执行的任何时候停止。此外,你为什么还要在事件循环中调用
run_in_executor
?新创建的线程不应该与运行事件循环的线程完全分开,以允许我们正在寻找的并发性吗?

我对可能发生的事情的唯一猜测是,由于

run_in_executor
返回协程(这也有点令人困惑——你如何从线程中获取协程?),
await
ing 这个协程会导致上下文切换在底层线程中,但我真的不知道你怎么能实现这样的东西。

python python-asyncio python-multithreading
1个回答
0
投票

你对协程和异步的理解是正确的。下面我们来分解一下事件循环、协程和线程之间的交互。

run_in_executor
是事件循环提供的一种方法,用于在单独的线程(或进程)中运行一个函数,并返回一个类似协程的对象(具体来说,是一个
asyncio.Future
)来表示该函数的最终结果。当您有一个要从运行事件循环的主线程卸载的阻塞操作时,这很有用。你是对的,线程是由操作系统调度的,并且可以在它们执行的任何时候停止,使它们成为抢占式多任务处理。

当您在事件循环上调用

run_in_executor
时,事件循环会创建一个新线程(或使用线程池中的现有线程)来执行您提供的功能。这个新线程确实与运行事件循环的主线程分开。你在事件循环上调用
run_in_executor
的原因是它允许事件循环管理并发并协调阻塞操作的结果与它已经处理的协程。

现在,让我们谈谈

run_in_executor
返回的类协程对象。当您
await
这个对象时,您不是在等待实际的线程,而是等待一个
asyncio.Future
对象,它表示您在单独的线程中运行的函数的结果。
Future
对象是计算最终结果的占位符。通过等待
Future
,事件循环可以继续执行其他协程,直到结果准备好。

当您在单独线程中运行的函数完成时,单独线程会使用结果或执行期间发生的任何异常更新

Future
对象。监视
Future
状态的事件循环看到结果已准备就绪,并安排等待
Future
的协程恢复执行。这样,事件循环管理协程和线程之间的并发,而不需要线程本身进行上下文切换。

综上所述,

run_in_executor
在事件循环上被调用,因为它允许事件循环管理协程和线程之间的并发。
run_in_executor
返回的类协程对象不是协程本身,而是代表阻塞操作最终结果的
asyncio.Future
。事件循环处理线程和协程之间的结果协调,允许并发执行。

© www.soinside.com 2019 - 2024. All rights reserved.