如果扩展是单线程的,是否需要 Python GIL

Is Python GIL needed if extension is single threaded

我正在为我的 Python 应用程序编写 C++ 扩展。我了解到 Python GIL 用于防止多个线程同时访问 PyObject。但是,我的问题是我的扩展代码是单线程的,我还需要获取 GIL 吗?

假设在 Python 应用程序中有一些代码,例如

import time
from threading import Thread

COUNT = 50000000

def countdown(n):
    while n>0:
        n -= 1

t1 = Thread(target=countdown, args=(COUNT//2,))
t2 = Thread(target=countdown, args=(COUNT//2,))

start = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()

print('Time taken in seconds -', end - start)

我知道虽然有2个线程,但是由于GIL,它们不会并行执行。如果我在两个线程中调用我的 c++ 扩展,而我的 c++ 扩展是单线程的,该怎么办?我需要考虑 GIL 吗?

或者另一个问题,我假设线程将尝试在 python 代码中保留 GIL。如果离开Python执行c++代码,GIL会不会被释放?

我假设我们正在谈论 CPython 并且它是 GIL。

该实现保证在解释器将控制权转移到您的 C++ 扩展时保留 GIL。这意味着您可以自由地调用解释器、检查任何对象等;任何其他需要访问解释器的线程都保证在尝试获取 GIL 时被阻塞。 这也意味着如果您的 C++ 扩展不关心 访问解释器的线程 ,那么它根本 不需要 考虑 GIL。 =10=]

这种 "safety-first" 方法的缺点是,当您的扩展代码正在执行时,实现会阻止 所有 对解释器的访问。如果您的扩展代码不需要访问解释器 - 例如因为它可以在本地工作 copies/buffers 或即将在 IO 上阻塞 - 那么你应该立即释放 GIL,以便其他线程可以 运行 并在 [=27= 之前重新获取它]给口译员。

考虑让两个 Python 线程尝试用新工作调用您的分机。第一个线程将被安排,阻塞解释器,调用你的扩展并等待它到 return。当它 returns 时,解释器切换到第二个线程,然后该线程才能调用您的扩展。现在它必须等待,阻塞线程 1。您有效地拥有永远不会 运行 并行的并发线程。从扩展中释放 GIL 允许其他线程取得进展。不过,不需要程序正确。