Paralelismo com Python Multiprocessing
--
Uma das grandes dificuldades de todo desenvolvedor é fazer com que seu código seja rápido. O problema é que muitas tarefas levam tempo para serem processadas, mesmo em computadores rápidos e com muitos núcleos.
Em partes, isso se deve ao GIL (Python Global Interpreter Lock) que permite que apenas uma Thread tome controle do interpretador Python.
Mas é possível driblar isso. Então, mãos à massa!
Imagine que você precisa rodar 3 funções que compõe um resultado final. Aqui neste exemplo, vamos calcular a soma de n com todos os n anteriores. Faremos isso 3x e mediremos o tempo de processamento.
Sem utilizar Multiprocessing (2 min e 4s):
from datetime import datetimestart = datetime.now()
def loop1():
for n in range(100000000):
result = (n*(n+1))/2
return resultdef loop2():
for n in range(200000000):
result = (n*(n+1))/2
return resultdef loop3():
for n in range(300000000):
result = (n*(n+1))/2
return resultresult = loop1() + loop2() + loop3()
print(f'Resultado: {result}')
print(f'Tempo: {datetime.now() - start}')>>> Resultado: 6.99999997e+16
>>> Tempo: 0:02:04.659429
Agora o próximo passo é instalar a biblioteca psutil.
Utilizando Multiprocessing e psutil (0 min e 59s):
from datetime import datetime
import multiprocessing as mp
import psutilstart = datetime.now()
def loop(core, r):
proc = psutil.Process()
proc.cpu_affinity([core])
for n in range(r):
result = (n*(n+1))/2
return resultcores = [0, 1, 2]
ranges = [100000000, 200000000, 300000000]
results = []if __name__ == '__main__':
with mp.Pool() as pool:
for core in cores:
p = pool.apply_async(func=loop, args=(core, ranges[core],))
results.append(p)
pool.close()
pool.join()
result = 0for p in results:
result = result + p.get()
print(f'Resultado: {result}')
print(f'Tempo: {datetime.now() - start}')>>> Resultado: 6.99999997e+16
>>> Tempo: 0:00:59.664461
Como podem ver, 3 núcleos (cores) estão sendo utilizados e felizmente obtivemos uma redução de aproximadamente 52% no tempo de processamento.
É possível reduzir ainda mais esse tempo? Sim, é possível, mas isso fica para outro post :)