¿Cuál es la forma más fácil de paralelizar este código?
Realmente me gusta concurrent.futures
para esto, disponible en Python3 desde la versión 3.2 , y a través de backport a 2.6 y 2.7 en PyPi .
Puede usar hilos o procesos y usar exactamente la misma interfaz.
Multiprocesamiento
Ponga esto en un archivo - futuretest.py:
import concurrent.futures
import time, random # add some random sleep time
offset = 2 # you don't supply these so
def calc_stuff(parameter=None): # these are examples.
sleep_time = random.choice([0, 1, 2, 3, 4, 5])
time.sleep(sleep_time)
return parameter / 2, sleep_time, parameter * parameter
def procedure(j): # just factoring out the
parameter = j * offset # procedure
# call the calculation
return calc_stuff(parameter=parameter)
def main():
output1 = list()
output2 = list()
output3 = list()
start = time.time() # let's see how long this takes
# we can swap out ProcessPoolExecutor for ThreadPoolExecutor
with concurrent.futures.ProcessPoolExecutor() as executor:
for out1, out2, out3 in executor.map(procedure, range(0, 10)):
# put results into correct output list
output1.append(out1)
output2.append(out2)
output3.append(out3)
finish = time.time()
# these kinds of format strings are only available on Python 3.6:
# time to upgrade!
print(f'original inputs: {repr(output1)}')
print(f'total time to execute {sum(output2)} = sum({repr(output2)})')
print(f'time saved by parallelizing: {sum(output2) - (finish-start)}')
print(f'returned in order given: {repr(output3)}')
if __name__ == '__main__':
main()
Y aquí está el resultado:
$ python3 -m futuretest
original inputs: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
total time to execute 33 = sum([0, 3, 3, 4, 3, 5, 1, 5, 5, 4])
time saved by parallellizing: 27.68999981880188
returned in order given: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
Multithreading
Ahora cambie ProcessPoolExecutor
a ThreadPoolExecutor
, y ejecutar el módulo nuevo:
$ python3 -m futuretest
original inputs: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
total time to execute 19 = sum([0, 2, 3, 5, 2, 0, 0, 3, 3, 1])
time saved by parallellizing: 13.992000102996826
returned in order given: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
¡Ahora ha realizado múltiples subprocesos y multiprocesamiento!
Nota sobre el rendimiento y el uso de ambos juntos.
El muestreo es demasiado pequeño para comparar los resultados.
Sin embargo, sospecho que el subprocesamiento múltiple será más rápido que el multiprocesamiento en general, especialmente en Windows, ya que Windows no admite la bifurcación, por lo que cada nuevo proceso debe tomarse un tiempo para iniciarse. En Linux o Mac, probablemente estarán más cerca.
Puede anidar múltiples subprocesos dentro de múltiples procesos, pero se recomienda no usar múltiples subprocesos para separar varios procesos.
calc_stuff
?