是否可以使用多线程模块从另一个正在运行的线程中释放锁定?我正在努力的用例是临时强制线程阻塞,然后解除阻塞。
from multiprocessing import Process
import time
def loop_forever():
while True:
pass
def pause_evaluation():
#Some code here that will force the other thread to release its GIL
def resume_evaluation():
#Some code here that will allow other thread to reacquire its GIL
def kill_evaluation():
global p_1
p_1.terminate()
def control_evaluation():
pause_evaluation()
time.sleep(30)
resume_evaluation()
time.sleep(30)
kill_evaluation()
p_1 = Process(target = loop_forever)
p_2 = Process(target = control_evaluation)
p_1.start()
p_2.start()
p_1.join()
p_2.join()
答案 0 :(得分:1)
您不能直接从threading
或multiprocessing
执行此操作,因为GIL版本的手动管理需要太多东西才能轻松地将其作为Python层API的一部分提供。
如果您愿意,可以改为创建C扩展模块并专门管理线程安全。手动创建的C扩展的常见模式如下:
#include "Python.h"
...
PyObject *manager_function(PyObject *self, PyObject *args) {
...
Py_BEGIN_ALLOW_THREADS
// Place threaded C code here.
// Disallowed from using Python API functions
...
Py_END_ALLOW_THREADS
...
return result;
}
在Cython中有nogil
上下文管理器,例如described here。
我认为一个低成本的解决方案是调查Cython中的cython.parallel
和nogil
选项,因为将代码移植到Cython可能并不太难,只需使用{ {1}}除了一个Python“驱动程序”函数之外的所有内容。
正如其他人在评论中指出的那样,CPython解释器有几种方式可以决定发布GIL。最常见的是,在主解释器循环中处理了一定数量的操作码后,事实上将释放GIL(默认值为100,可以使用cdef
进行调整,并且可以使用{ {1}})。
此外,当解释器识别出正在等待I / O的线程时,它可能会释放GIL。在这种情况下,即使在GIL的Python中,您也可以通过简单的旧线程实现并发计算。一些线程很乐意执行解释器操作代码,同时另一个线程正在等待套接字读取信号或来自某些I / O源的东西。
最终,当I / O线程准备好完成读取时,GIL将再次释放,并且程序将停止并发并恢复跨多个线程的完全同步执行。这一切都发生在幕后,并没有由程序员明确管理。