2015-11-27 7 views
3

C код встроенной функции обратного вызова python и помещает данные в очередь python через обратный вызов, когда я получаю данные из очереди, это очень медленно.C код встроенная функция обратного вызова python

Пример:

с код, как этот

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); 
    } 
} 

собрать этот код на С так, как mywrap.so, и импортировать это так в 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.

ответ

1

Я думаю, что ваш код C никогда не освобождает блокировку глобального интерпретатора (GIL), поэтому ваш код на Python никогда не будет работать. Когда вы запускаете несколько потоков в коде Python, они автоматически меняют GIL между ними и поэтому одинаково распределяют время, но это не происходит без вашего вмешательства в C-код.

Возможно, он будет работать намного лучше, если вы приобретете и отпустите GIL один раз за цикл в своем C-коде (даже если вы ничего не делаете, что не ему нужно). Все, что я действительно сделал, добавили макросы Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_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% уверен, что это правильно, но я был неправ раньше!)

+0

(Я редактировал это - мой исходный код был два макроса ошибочно, так что бы не сработало - извините!) – DavidW

+0

ваше предложение замечательно, оно работает! Огромное спасибо. Я запускаю код как ваше предложение, оно работает, но когда я вставляю Py_BEGIN_ALLOW_THREADS в начале func и добавляю Py_END_ALLOW_THREADS перед возвратом. я запускаю его, это сегментный отказ, почему это? – ICYMYM

+0

Это потому, что я ошибся! (теперь исправлено). Вам не разрешены вызовы api Python между 'Py_BEGIN_ALLOW_THREADS' и' Py_END_ALLOW_THREADS'. Таким образом, любая из функций, начинающихся с 'Py', не будет работать. К сожалению, ни один из этих кодов не может работать параллельно - я только что добавил место, где он может меняться между вашим модулем C и вашим кодом Python. – DavidW

Смежные вопросы