如何证明多线程下用c调用python的时候,python会定期切换出当前的线程,释放GIL

如何证明多线程下用c调用python的时候,python会定期切换出当前的线程,释放全局锁,然后换给其他线程执行

基本思路:在调用的python函数中,让这个函数睡眠2秒钟,此时这个线程拿到了GIL,按理说应该等这个线程函数睡足了2秒钟才切换到下一个线程。

import time
def my_pFun(a, l):
    print "a = : " + str(a)
    print str(l) + " : start time" + str(time.time())
    time.sleep(2)    #三个线程都调用这个函数,睡眠2秒钟
    print str(l) + " : end time" + str(time.time())
#include <Python.h>
#include <pthread.h>
#include <iostream>

using namespace std;

class PyThreadStateLock
{
public:
    PyThreadStateLock()
    {
        state = PyGILState_Ensure();
    }
    ~PyThreadStateLock()
    {
        PyGILState_Release(state);
    }
private:
    PyGILState_STATE state;
    
};

PyObject* pFunc = NULL;
void pFunc_init()
{

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");
    //PyRun_SimpleString("import time");

    PyObject* pyModule = PyImport_Import(PyString_FromString("mypy"));
    if(pyModule == NULL)
    {
        printf("load mypy failed\n");
        exit(0);
    }
    PyObject* pDict = PyModule_GetDict(pyModule);
    pFunc = PyDict_GetItemString(pDict, "my_pFun");
}

void * threadFunc(void* arg)
{
    //PyEval_ReleaseLock();
    long tid = pthread_self();
    pthread_detach(pthread_self());
    PyObject* pkwargs = NULL;    
    PyThreadStateLock PyThreadLock;
    int a = *(int*)arg;
    delete (int*)arg;

    cout << "********in thread:" << pthread_self() <<  " **** a:" << a << endl;
    PyObject* pArgs = PyTuple_New(2);
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", a));
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("l", tid));
    PyObject_Call(pFunc, pArgs, pkwargs);
    cout << "c sleep in : " << pthread_self() << endl;
    sleep(3);
    //exit(0);
    //pthread_exit(NULL);

}


int main(int argc, char  *argv[])
{
    Py_Initialize();
    PyEval_InitThreads();
    pFunc_init();

    pthread_t tid[3];
    PyEval_ReleaseThread(PyThreadState_Get());
    for(int i = 0; i < 3; i++)
    {
        int* j = new int(i);
        pthread_create(&tid[i], NULL, threadFunc, j);
    }


    for(int i = 0; i < 3; i++)
    {
        pthread_join(tid[i], NULL);
    }

    PyGILState_Ensure();
    Py_Finalize();
    return 0;
}

运行结果可以看到,这三个线程函数中的sleep几乎是同时开始的,然后几乎是同时结束的,可以看出,在操作系统的底层,会对占用GIL的线程进行定期的切换,当第一个线程开始sleep之后,马上换到第二个线程去执行,当它睡眠之后,又换到第三个线程执行,切换的时候肯定保存了线程执行的上下文,以便再次被调度继续执行。所以这三个python程序的sleep几乎是同时进行,同时结束的,所以可以说明,python的多线程处理阻塞性(比如IO)任务还是可以的。



展开阅读全文

没有更多推荐了,返回首页