Cython进阶--用Cython封装Callback函数(续)

心的人可能已经发现了,在《Cython进阶--Cython封装Callback函数》中,每次获取GIL都要调用一下PyGILState_Ensure,释放时又要调用PyGILState_Release

为了防止已经获取GIL的线程在执行I/O操作而导致其它运行Python代码的线程暂时获取不到GIL而被迫暂停,更有甚者如果已经获取GIL的线程调用的某一个C函数在等待一个mutex,而另一个负责释放这个锁的线程却在等待获取GIL,根本无法释放这个mutex,那就造成了死锁!为了避免这种情况的发生,就要在调用C函数之前调用PyEval_SaveThread 暂时释放GIL,函数调用完时调用PyEval_RestoreThread重新获取。


这样是不是太麻烦了,实际上,cython的设计者们早就为我们考虑到了这点,方法就是用with gilwith nogil语句块。

这也再一次印证了一句话:只有想不到的,没有做不到的

你在遇到一个问题时,99.99999999%的概率别人已经解决过了,如果恰巧碰上了0.0000000001%的概率,那么你应该感到幸运。


先来看下面的例子:

 


cdef extern from"pthread.h":

    ctypedef void * pthread_t

    ctypedef struct pthread_attr_t:

        pass

    int pthread_create (pthread_t *__newthread,\

                   pthread_attr_t *__attr, \

                   void*(*__start_routine)(void *)except*, \

                   void *__arg)

                  

    int pthread_join (pthread_t __th,void**__thread_return) nogil

cdef extern from"Python.h":

    ctypedef enum PyGILState_STATE:

        pass

    ctypedef enum PyThreadState:

        pass

    void PyEval_InitThreads()

    void Py_INCREF(object obj)

    void Py_DECREF(object obj)

 

def Callback(obj):

    if hasattr(obj,'run'):

        obj.run()

cdef void * start (void *param)except*with gil:

    cdef object obj = param

    cdef void *ret

    ifnot param:

        return 
    
    
     
     0

    Callback(obj)

    Py_DECREF(obj)

 

    return 
     
     
      
      1

 

def CreateThread(obj):

    cdef int ret

    cdef pthread_t tid

    PyEval_InitThreads()

    Py_INCREF(obj)

    ret = pthread_create(&tid,
      
      
       
       0, start,
       
       
         obj) if ret != -1: return 
        
          tid else: Py_DECREF(obj) returnNone def JoinThread(int tid): cdef void *thread_return = 
         
           0 cdef int ret with nogil: ret =pthread_join( 
          
            tid,&thread_return) if ret != -1: return 
           
             thread_return else: return 
            
              0 
             
  

   

首先,在引用pthread_join函数时在文件尾加上了 nogil,表明这个函数可以在with nogil语句块中调用,要不然cython在翻译成c代码的时候报错

 

    int pthread_join (pthread_t __th,void**__thread_return) nogil

 

再就是在JoinThread时改用了如下的调用方法:

 

    with nogil:

 

        ret =pthread_join(<pthread_t>tid,&thread_return)

可见要比原来的方法简单多了

 

再来看下start函数的声明,

 

cdef void * start (void *param)except*with gil:

在最后加上了with gil,表明这个函数在调用时会先获取GIL

 

有兴趣的可以看下生成的C代码,

 

with gil会生成如下的代码:

 

  #ifdefWITH_THREAD

  PyGILState_STATE __pyx_gilstate_save =PyGILState_Ensure();

  #endif

 

...

 

  #ifdefWITH_THREAD

  PyGILState_Release(__pyx_gilstate_save);

  #endif

 

with nogil会生成如下的代码:

 

      #ifdefWITH_THREAD

      PyThreadState *_save;

      Py_UNBLOCK_THREADS

      #endif

 

...

 

 

        #ifdef WITH_THREAD

        Py_BLOCK_THREADS

        #endif

 

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值