GIL分析

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章