135 votes

Multiprocessing : utiliser tqdm pour afficher une barre de progression

Pour rendre mon code plus "pythonique" et plus rapide, j'utilise le "multitraitement" et une fonction de cartographie pour lui envoyer a) la fonction et b) la gamme d'itérations.

La solution implantée (c'est-à-dire appeler tqdm directement sur la plage tqdm.tqdm(plage(0, 30)) ne fonctionne pas avec le multitraitement (comme formulé dans le code ci-dessous).

La barre de progression est affichée de 0 à 100% (lorsque python lit le code ?) mais elle n'indique pas la progression réelle de la fonction map.

Comment afficher une barre de progression qui indique à quelle étape se trouve la fonction 'map' ?

from multiprocessing import Pool
import tqdm
import time

def _foo(my_number):
   square = my_number * my_number
   time.sleep(1)
   return square 

if __name__ == '__main__':
   p = Pool(2)
   r = p.map(_foo, tqdm.tqdm(range(0, 30)))
   p.close()
   p.join()

Toute aide ou suggestion est la bienvenue...

168voto

hkyi Points 154

Utilisez imap au lieu de map, qui renvoie un itérateur de valeurs traitées.

from multiprocessing import Pool
import tqdm
import time

def _foo(my_number):
   square = my_number * my_number
   time.sleep(1)
   return square 

if __name__ == '__main__':
   with Pool(2) as p:
      r = list(tqdm.tqdm(p.imap(_foo, range(30)), total=30))

62voto

SciPy Points 759

Solution trouvée : Attention ! En raison du multiprocesseur, le temps d'estimation (itération par boucle, temps total, etc.) pourrait être instable, mais la barre de progression fonctionne parfaitement.

Remarque : Le gestionnaire de contexte pour Pool n'est disponible qu'à partir de la version 3.3 de Python.

from multiprocessing import Pool
import time
from tqdm import *

def _foo(my_number):
   square = my_number * my_number
   time.sleep(1)
   return square 

if __name__ == '__main__':
    with Pool(processes=2) as p:
        max_ = 30
        with tqdm(total=max_) as pbar:
            for i, _ in tqdm(enumerate(p.imap_unordered(_foo, range(0, max_)))):
                pbar.update()

29voto

Victor Quach Points 1

Vous pouvez utiliser p_tqdm à la place.

https://github.com/swansonk14/p_tqdm

from p_tqdm import p_map
import time

def _foo(my_number):
   square = my_number * my_number
   time.sleep(1)
   return square 

if __name__ == '__main__':
   r = p_map(_foo, list(range(0, 30)))

9voto

Oli Blum Points 864

En me basant sur la réponse de Xavi Martínez, j'ai écrit la fonction imap_unordered_bar . Il peut être utilisé de la même manière que imap_unordered à la seule différence qu'une barre de traitement est affichée.

from multiprocessing import Pool
import time
from tqdm import *

def imap_unordered_bar(func, args, n_processes = 2):
    p = Pool(n_processes)
    res_list = []
    with tqdm(total = len(args)) as pbar:
        for i, res in tqdm(enumerate(p.imap_unordered(func, args))):
            pbar.update()
            res_list.append(res)
    pbar.close()
    p.close()
    p.join()
    return res_list

def _foo(my_number):
    square = my_number * my_number
    time.sleep(1)
    return square 

if __name__ == '__main__':
    result = imap_unordered_bar(_foo, range(5))

1voto

BlueTomato Points 711
import multiprocessing as mp
import tqdm

some_iterable = ...

def some_func():
    # your logic
    ...

if __name__ == '__main__':
    with mp.Pool(mp.cpu_count()-2) as p:
        list(tqdm.tqdm(p.imap(some_func, iterable), total=len(iterable)))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X