2011-03-12 13 views
6

Estoy construyendo una clase de subprocesos para ejecutar consultas MySQL usando Python y MySQLdb. No entiendo por qué ejecutar estas consultas enhebradas es más lento que ejecutarlas sin subprocesos. Aquí está mi código para mostrar lo que estoy haciendo.¿Por qué las consultas MySQLdb enhebradas en Python son más lentas que las mismas consultas sin subprocesos?

Primero, aquí está la función no roscada.

def testQueryDo(query_list): 

    db = MySQLdb.connect('localhost', 'user', 'pass', 'db_name') 
    cursor = db.cursor() 

    q_list = query_list 
    for each in q_list: 
     cursor.execute(each) 
     results = cursor.fetchall() 

    db.close() 

Aquí es mi clase de roscado:

class queryThread(threading.Thread): 

    def __init__(self, queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 

     self.db = MySQLdb.connect('localhost', 'user', 'pass', 'db_name') 
     self.cursor = self.db.cursor() 

    def run(self): 
     cur_query = self.queue.get() 
     self.cursor.execute(cur_query) 
     results = self.cursor.fetchall() 
     self.db.close() 
     self.queue.task_done() 

Y es el manejador aquí:

def queryHandler(query_list): 
    queue = Queue.Queue() 

    for query in query_list: 
     queue.put(query) 

    total_queries = len(query_list) 
    for query in range(total_queries): 
     t = queryThread(queue) 
     t.setDaemon(True) 
     t.start() 

    queue.join() 

No estoy seguro de por qué este código roscado va más lento. Lo que es interesante es que si uso el mismo código, solo hago algo simple como agregar números, el código enhebrado es significativamente más más rápido.

Entiendo que me debe estar perdiendo algo completamente obvio, sin embargo cualquier ayuda sería muy apreciada.

Respuesta

2

Está iniciando N subprocesos, cada uno de los cuales crea su propia conexión a MySQL, y está utilizando una cola sincrónica para entregar las consultas a los subprocesos. Cada hilo está bloqueando en queue.get() (adquiriendo un bloqueo exclusivo) para obtener una consulta, luego creando una conexión a la base de datos, y luego llamando al task_done() que permite que el siguiente hilo proceda. Entonces, mientras el hilo 1 está funcionando, los hilos N-1 no están haciendo nada. Esta sobrecarga de bloqueo adquiere/libera, más la sobrecarga adicional de crear y cerrar en serie varias conexiones a la base de datos.

+0

También CPython solo permite la ejecución de un hilo a la vez (debido a GIL) incluso si ... –

+0

¡Ah, tenía la impresión de que se estaban ejecutando simultáneamente! Gracias samplebias! ¿Sería más eficiente si utilizo múltiples procesos para bifurcar cada consulta, o hay una forma mejor/más eficiente de hacerlo con el hilo que me falta? – mudda

+0

Realmente depende de su aplicación, pero algunas cosas mejorarán el rendimiento de su ejemplo anterior: use un threadpool más pequeño y envíe varias consultas a cada thread en lugar de uno, haga que cada thread reutilice su conexión a la base de datos para múltiples consultas. Si decide usar 'fork', puede probar el módulo [multiprocesamiento] (http://docs.python.org/library/multiprocessing.html) para facilitar la comunicación con sus subprocesos. – samplebias

Cuestiones relacionadas