Qual è il modo più semplice per parallelizzare questo codice?
Mi piace molto concurrent.futures
per questo, disponibile in Python3 dalla versione 3.2 - e tramite backport a 2.6 e 2.7 in poi PyPi .
È possibile utilizzare thread o processi e utilizzare esattamente la stessa interfaccia.
multiprocessing
Metti questo in un file - 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()
Ed ecco l'output:
$ 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
Ora ProcessPoolExecutor
passa a ThreadPoolExecutor
ed esegui di nuovo il modulo:
$ 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]
Ora hai fatto sia il multithreading che il multiprocessing!
Nota sulle prestazioni e sull'uso di entrambi insieme.
Il campionamento è troppo piccolo per confrontare i risultati.
Tuttavia, sospetto che il multithreading sarà più veloce del multiprocessing in generale, soprattutto su Windows, poiché Windows non supporta il fork, quindi ogni nuovo processo deve richiedere del tempo per l'avvio. Su Linux o Mac probabilmente saranno più vicini.
È possibile nidificare più thread all'interno di più processi, ma si consiglia di non utilizzare più thread per escludere più processi.
calc_stuff
?