什么是GIL
GIL英文全称global interpreter lock,cpython中引入的一种机制,用来保证在同一时间内只有一个线程能够执行。GIL并不是python独有的,在许多其他语言中也有GIL的身影。在cpython中,GIL本质上是一个全局互斥锁。
GIL保护了什么
Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
GIL是一直存在的吗?
GIL既然是为了解决多线程模式下对虚拟机的使用权问题,如果对一个简单计数脚本来启动GIL(相当于启动了多线程编程)那肯定是会让人抓狂的。对多线程的支持并非没有代价,最简单的一点,如果程序中没有多线程但是启动了GLI,那么每执行100个命令,python虚拟机就会激活线程的调度。而如果不激活多线程,那么旧不需要做这些无用功,python选择了由开发者自己手动激活多线程。在python虚拟机启动是,多线程机制并没有激活,他支持单线程,如果用户调用了thread_start_new_thread,明确的指示python虚拟机创建新的线程,python就意识到用户需要多线程,这是时候,python虚拟机会自动创建需要的数据结构、环境以及至关重要的GIL
GIL的创建过程
python多线程的创建过程就是GIL的初始化过程。通过分析多线程来查看GIL的创建过程。
python创建一个线程的过程。
/*
* Modules/threadmodule.c
*/
static PyObject *
thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
{
PyObject *func, *args, *keyw = NULL;
struct bootstate *boot;
long ident;
if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
&func, &args, &keyw))
return NULL;
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError,
"first arg must be callable");
return NULL;
}
if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_TypeError,
"2nd arg must be a tuple");
return NULL;
}
if (keyw != NULL && !PyDict_Check(keyw)) {
PyErr_SetString(PyExc_TypeError,
"optional 3rd arg must be a dictionary");
return NULL;
}
boot = PyMem_NEW(struct bootstate, 1);
if (boot == NULL)
return PyErr_NoMemory();
boot->interp = PyThreadState_GET()->interp;
boot->func = func;
boot->args = args;
boot->keyw = keyw;
boot->tstate = _PyThreadState_Prealloc(boot->interp);
if (boot->tstate == NULL) {
PyMem_DEL(boot);
return PyErr_NoMemory();
}
Py_INCREF(func);
Py_INCREF(args);
Py_XINCREF(keyw);
PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
if (ident == -1) {
PyErr_SetString(ThreadError, "can't start new thread");
Py_DECREF(func);
Py_DECREF(args);
Py_XDECREF(keyw);
PyThreadState_Clear(boot->tstate);
PyMem_DEL(boot);
return NULL;
}
return PyInt_FromLong(ident);
}
/*
* Python/cevel.c
*/
static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */
void
PyEval_InitThreads(void)
{
if (interpreter_lock)
return;
interpreter_lock = PyThread_allocate_lock();
PyThread_acquire_lock(interpreter_lock, 1);
main_thread = PyThread_get_thread_ident();
}
/*
* Lock support. Python/thread_pthread.h
*/
PyThread_type_lock
PyThread_allocate_lock(void)
{
sem_t *lock;
int status, error = 0;
dprintf(("PyThread_allocate_lock called\n"));
if (!initialized)
PyThread_init_thread();
lock = (sem_t *)malloc(sizeof(sem_t));
if (lock) {
status = sem_init(lock,0,1);
CHECK_STATUS("sem_init");
if (error) {
free((void *)lock);
lock = NULL;
}
}
dprintf(("PyThread_allocate_lock() -> %p\n", lock));
return (PyThread_type_lock)lock;
}
typedef struct {
char locked; /* 0=unlocked, 1=locked */
/* a <cond, mutex> pair to handle an acquire of a locked lock */
pthread_cond_t lock_released;
pthread_mutex_t mut;
}
至此GIL终于被创建出来了….