asyncio 是否受 GIL 影响?

Mee*_*ger 9 python multithreading gil python-asyncio

在这个页面上我读到了这样的内容:

asyncio 模块中的协程不受全局解释器锁或 GIL 的限制。

asyncio但是,如果事件循环和threading线程都在带有 GIL 的单个 Python 进程中运行,这怎么可能呢?

据我了解, GIL 对 的影响asyncio不会像对 那样强烈threading,因为在 的情况下threading,解释器会切换到无用的操作,例如time.sleep()。因此,在使用时asyncio,建议使用asyncio.sleep().

据我所知,这些工具的设计目的略有不同,threading更常用于执行 IO 绑定操作的“遗留”阻塞代码,以及asyncio非阻塞代码。

Mis*_*agi 13

对此实际上有两种答案,具体取决于您是将 GIL 作为具体实现还是概念限制。前者的答案是“不”,后者的答案是“是”。


asyncio并发性不受 GIL 的约束。

GIL 的存在是为了同步线程并发:当多个线程同时处于活动状态时,只有拥有 GIL 的线程才能执行 Python 代码。这意味着如果另一个线程需要运行,GIL 的所有权必须从当前执行线程传递给另一个线程。这是通过抢占式并发实现的,这意味着当前正在执行的线程会定期强制暂停。
因此,GIL 是处理当前执行线程和所有其他线程之间控制权切换的机制。这是一种非常浪费的机制,线程越多,情况就会变得越糟。

相反,asyncio它有自己的并发同步:async/通过设计await提供协作并发。这意味着当前正在执行的任务可以自愿将控制权交给任何其他等待的任务。这允许asyncio事件循环自由地调度任务。
因此,GIL 不参与当前正在执行的任务和所有其他任务之间的控制切换。无论任务数量如何,async诸如此类的框架都可以实现非常高效的任务切换。asyncio


是的asyncio受 GIL 约束。

虽然asyncio可以有效地切换任务,但它不能同时运行多个任务。因此,它实际上并没有避免 GIL 的概念限制:一次运行多个操作。虽然asyncio应用程序避免了GIL 对于许多操作的低效率,但它并不能避免GIL 对于并行操作的限制。
值得注意的是,解决这一限制需要解决与删除 GIL 完全相同的挑战:在并行执行 Python 代码时提供安全同步。

此外,asyncio仍然无法作为任务同时执行阻塞代码,但必须回退到线程处理这些代码。因此,asyncio并发执行阻塞代码的后端直接受GIL约束。

  • @roganjosh通过[async/await的力量](/sf/ask/3430395601/)。TLDR 是“asyncio”任务可以以与生成器“yield”相同的方式产生。例如,您可以将多个生成器上的“zip”视为(非常)原始的事件循环。 (2认同)

Dan*_*erg 6

问题的答案

asyncio受GIL影响吗?

取决于你所说的“受影响”到底是什么意思。

Python 文档将GIL定义为

CPython 解释器使用一种机制来确保一次只有一个线程执行 Python 字节码。

由于asyncio事件循环始终在单个线程中运行,因此我认为您使用asyncio.

但是,当然,当您使用asyncio. (一个流行的例子是ThreadPoolExecutor与 一起使用run_in_executor。)

在这种情况下,GIL 的限制当然适用

为了公平对待您引用的文章,作者在几句话后限定了他的陈述:

GIL 的概念在协程上下文中没有意义,因为事件循环中的所有协程都在单个线程中执行。

我会很仁慈地解释这本质上是“GIL 在协程的上下文中并不重要”。记住我上面提到的警告,这是很公平的。