什麼是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終於被創建出來了….