从另一个线程释放解释器锁/强制另一个线程阻塞

时间:2016-03-04 16:51:35

标签: python multithreading

是否可以使用多线程模块从另一个正在运行的线程中释放锁定?我正在努力的用例是临时强制线程阻塞,然后解除阻塞。

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()

1 个答案:

答案 0 :(得分:1)

您不能直接从threadingmultiprocessing执行此操作,因为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.parallelnogil选项,因为将代码移植到Cython可能并不太难,只需使用{ {1}}除了一个Python“驱动程序”函数之外的所有内容。

正如其他人在评论中指出的那样,CPython解释器有几种方式可以决定发布GIL。最常见的是,在主解释器循环中处理了一定数量的操作码后,事实上将释放GIL(默认值为100,可以使用cdef进行调整,并且可以使用{ {1}})。

此外,当解释器识别出正在等待I / O的线程时,它可能会释放GIL。在这种情况下,即使在GIL的Python中,您也可以通过简单的旧线程实现并发计算。一些线程很乐意执行解释器操作代码,同时另一个线程正在等待套接字读取信号或来自某些I / O源的东西。

最终,当I / O线程准备好完成读取时,GIL将再次释放,并且程序将停止并发并恢复跨多个线程的完全同步执行。这一切都发生在幕后,并没有由程序员明确管理。