假设我有一个C扩展函数,它可以完全独立于Python解释器。 不是否有任何理由释放GIL?
例如,有没有理由不编写这样的代码(除了可读性和避免微优化之类的问题 - 重要的事情,但与我的问题无关)?
Py_BEGIN_ALLOW_THREADS
a = 1 + 1;
Py_END_ALLOW_THREADS
显然,这是一个简单的代码,其中性能可能无关紧要。但是否有任何性能原因不在这里发布GIL?或者只应发布GIL以获得更多CPU密集型代码?
答案 0 :(得分:7)
GIL是普通的互斥锁。锁定或解锁无争议互斥锁的成本非常低,不会超过更改全局变量的成本。但是,如果经常锁定和解锁有争议的互斥锁,则互斥锁的成本会变得很高。
所以,这通常不是一个好主意:
Py_BEGIN_ALLOW_THREADS
a = 1 + 1;
Py_END_ALLOW_THREADS
这里发生的事情是你正在解锁你之后立即再次尝试锁定的互斥锁。如果这是两个大块代码之间的中断,那么它为另一个线程提供了运行的机会。但是如果您没有线程粒度问题,请保持锁定。
所以在这种背景下这是一个好主意:
very_long_computation_requires_gil();
Py_BEGIN_ALLOW_THREADS;
a = a + i;
Py_END_ALLOW_THREADS;
very_long_computation_also_requires_gil();
如果不了解上下文就不可能做出有根据的猜测,如果没有运行测试,通常仍然很难。
答案 1 :(得分:2)
专家们仍在调整和测试GIL。
这是关于旧问题的新想法: inside-look-at-gil-removal-patch
你也可以考虑尝试Stackless Python(没有GIL)或PyPy(带有Just-In-Time编译器的Python)。
答案 2 :(得分:0)
如果你有一个C扩展函数可以完全独立于Python解释器,那么释放GIL通常是一个好主意。唯一的缺点就是等待GIL回归。在Python 3.2中,您必须等待至少1/20秒。
答案 3 :(得分:0)
有没有理由不释放GIL?
如果C扩展名调用非重入代码,那么如果多个Python线程同时调用扩展名,则可能会出现问题。因此,您可能希望避免在此类扩展中发布GIL以防止发生这种情况(当然,您可以在Python级别或C级别创建自己的互斥锁,以实现此目的而不影响其他线程)。
或者只应发布GIL以获得更多CPU密集型代码?
释放GIL的另一个主要原因是调用阻塞的C扩展(例如套接字上的阻塞读取)以启用其他线程。这正是Python解释器本身在线程中执行阻塞操作时发生的情况。