C代码嵌入python回调函数

C代码嵌入python回调函数,python,c,callback,queue,cython,Python,C,Callback,Queue,Cython,C代码嵌入python回调函数,并通过回调将数据放入python队列,当我从队列中获取数据时,速度非常慢 例如: 像这样的c代码 static int wrap_func(const int a, const unsigned char *b) { long ret; PyObject *arglist; PyObject * result = NULL; arglist = Py_BuildValue("(s#)", b, a); result = PyEval_Call

C代码嵌入python回调函数,并通过回调将数据放入python队列,当我从队列中获取数据时,速度非常慢

例如:

像这样的c代码

static int wrap_func(const int a, const unsigned char *b)
{
  long ret;
  PyObject *arglist;
  PyObject * result = NULL;

  arglist = Py_BuildValue("(s#)", b, a);
  result = PyEval_CallObject(my_callback, arglist);

  /* evaluate result or handle exception */
  ret = PyInt_AsLong(result);
  if (result == NULL)
    return -1;
  Py_DECREF(result);

  return ret;
}

void produce_data()
{
    while(1){
        //produce data to buffer, len is buffer length
        //call callback func 
        wrap_func(buffer, len);
    }
}
将此c代码编译为类似于mywrap.so的形式,并将其导入python中 python代码如下:

import multiprocessing
import mywarp   # mywrap.so

class WorkerThread_a(threading.Thread):
    def __init__(self, workQueue):
        threading.Thread.__init__(self)
        self.workQueue = workQueue
        self.setDaemon(True)
    def run(self):
        while 1:
            try:
                recvdata = self.workQueue.get(block=False)
            except Queue.Empty:
                continue
            #do sth use recvdata

workQueue = multiprocessing.Queue()

def callback_func(a):
    if a:
        workQueue.put(a)
    return 0

def main():
    tmp = WorkerThread_a(workQueue)
    tmp.start()
    mywarp.set_callback(callback_func)
    mywarp.decode_audio()

main()
在python线程中,我从队列中获取数据,但获取数据的速度非常慢,但在c中,通过python回调函数快速生成数据并放入队列


如何像在纯python代码中一样快速地从队列中获取数据。

我认为发生的事情是,您的C代码从未释放全局解释器锁(GIL),因此您的python代码永远没有机会运行。当您在Python代码中运行多个线程时,它们会自动在它们之间交换GIL,从而平等地共享时间,但是如果您不干预C代码,这是不会发生的

如果您在C代码中每个循环获取并发布一次GIL(即使您不做任何不需要它的事情),它可能会工作得更好。我真正做的就是在函数的开头添加宏
Py\u BEGIN\u ALLOW\u THREADS
Py\u END\u ALLOW\u THREADS

static int wrap_func(const int a, const unsigned char *b)
{
  Py_BEGIN_ALLOW_THREADS /* ADDED! */
  /* This should give the chance for the main Python thread
  to run, even though no code goes here */
  Py_END_ALLOW_THREADS /* ADDED */

  long ret;
  PyObject *arglist;
  PyObject * result = NULL;

  arglist = Py_BuildValue("(s#)", b, a);
  result = PyEval_CallObject(my_callback, arglist);

  /* evaluate result or handle exception */
  ret = PyInt_AsLong(result);

  /* This is chang */
  if (result == NULL)
    return -1;
  Py_DECREF(result);


  return ret;
}

(我应该说-这是一个未经测试的猜测,我90%肯定是对的,但我以前就错了!)

(我编辑过这个-我的原始代码错误地使用了两个宏,所以不会工作-抱歉!)你的建议很好,很有效!非常感谢。我按照您的建议运行代码,它是有效的,但是当我将Py\u BEGIN\u ALLOW\u线程放在func的开头,并在返回之前放置Py\u END\u ALLOW\u线程时。我运行它,这是段错误,这是为什么?那是因为我犯了一个错误!(现已修复)。不允许在
Py\u BEGIN\u ALLOW\u THREADS
Py\u END\u ALLOW\u THREADS
之间进行任何Python api调用。因此,这意味着任何以
Py
开头的函数都无法工作。不幸的是,这些代码实际上都不能并行运行——我刚刚添加了一个地方,可以在C模块和Python代码之间进行交换。