Python multi-threading más lento que la serie?

Estoy tratando de averiguar la progtwigción de subprocesos múltiples en Python. Aquí está la tarea simple con la que quiero comparar las velocidades en serie y en paralelo.

import threading import Queue import time import math def sinFunc(offset, n): result = [] for i in range(n): result.append(math.sin(offset + i * i)) return result def timeSerial(k, n): t1 = time.time() answers = [] for i in range(k): answers.append(sinFunc(i, n)) t2 = time.time() print "Serial time elapsed: %f" % (t2-t1) class Worker(threading.Thread): def __init__(self, queue, name): self.__queue = queue threading.Thread.__init__(self) self.name = name def process(self, item): offset, n = item self.__queue.put(sinFunc(offset, n)) self.__queue.task_done() self.__queue.task_done() def run(self): while 1: item = self.__queue.get() if item is None: self.__queue.task_done() break self.process(item) def timeParallel(k, n, numThreads): t1 = time.time() queue = Queue.Queue(0) for i in range(k): queue.put((i, n)) for i in range(numThreads): queue.put(None) for i in range(numThreads): Worker(queue, i).start() queue.join() t2 = time.time() print "Serial time elapsed: %f" % (t2-t1) if __name__ == '__main__': n = 100000 k = 100 numThreads = 10 timeSerial(k, n) timeParallel(k, n, numThreads) #Serial time elapsed: 2.350883 #Serial time elapsed: 2.843030 

¿Puede alguien explicarme lo que está pasando? Estoy acostumbrado a C ++, y una versión similar de esto utilizando el módulo ve la velocidad que esperaríamos.

Related of "Python multi-threading más lento que la serie?"

Otras respuestas se han referido al problema de que GIL es el problema en cpython. Pero sentí que faltaba un poco de información. Esto causará problemas de rendimiento en situaciones en las que el código que está ejecutando en subprocesos está vinculado a la CPU. En su caso aquí, sí, hacer muchos cálculos en subprocesos probablemente resultará en un rendimiento dramáticamente degradado.

Pero, si estaba haciendo algo que estaba más ligado a la E / S, como leer desde muchos sockets en una aplicación de red, o llamar al subproceso, puede obtener aumentos de rendimiento de los subprocesos. Un ejemplo simple para su código anterior sería agregar una llamada estúpidamente simple al shell:

 import os def sinFunc(offset, n): result = [] for i in xrange(n): result.append(math.sin(offset + i * i)) os.system("echo 'could be a database query' >> /dev/null; sleep .1") return result 

Esa llamada podría haber sido algo real, como esperar en el sistema de archivos. Pero puede ver que en este ejemplo, el subproceso comenzará a ser beneficioso, ya que la GIL puede liberarse cuando el subproceso está esperando en IO y otros subprocesos continuarán procesándose. Aun así, todavía hay un punto dulce para cuando más subprocesos comienzan a negarse por la sobrecarga de crearlos y sincronizarlos.

Para el código enlazado de la CPU, usted haría uso de multiprocesamiento

Del artículo: http://www.informit.com/articles/article.aspx?p=1850445&seqNum=9

… el subproceso es más apropiado para las aplicaciones enlazadas a E / S (I / O libera la GIL, lo que permite una mayor concurrencia) …

Referencias de preguntas similares sobre los procesos de subprocesos vs:
https://stackoverflow.com/a/1227204/496445
https://stackoverflow.com/a/990436/496445

Python tiene un problema grave de subprocesos. Básicamente, agregar subprocesos a una aplicación de Python casi siempre falla al hacerlo más rápido y, a veces, lo hace más lento.

Esto se debe al locking global del intérprete , o GIL.

Aquí hay una publicación del blog sobre eso que incluye una charla sobre el tema.

Una forma de evitar esta limitación es usar procesos en lugar de subprocesos; Esto se hace más fácil por el módulo de multiprocesamiento .

Las bibliotecas de Python que están escritas en C pueden obtener / liberar el locking de intérprete global (GIL) a voluntad. Aquellos que no usan objetos de Python pueden lanzar la GIL para que otros subprocesos puedan obtener una apariencia, sin embargo, creo que la biblioteca matemática usa objetos de Python todo el tiempo, por lo que efectivamente math.sin se serializa. Como el locking / deslocking es una sobrecarga, no es raro que los hilos de Python sean más lentos que los procesos.