Многопроцессорность: используйте tqdm для отображения индикатора выполнения

Чтобы сделать мой код более "питоническим" и более быстрым, я использую "многопроцессорность" и функцию карты, чтобы отправить ее: а) функцию и б) диапазон итераций.

Имплантированное решение (т.е. Вызов tqdm непосредственно в диапазоне tqdm.tqdm (диапазон (0, 30)) не работает с многопроцессорностью (как сформулировано в коде ниже).

Индикатор выполнения отображается от 0 до 100% (когда питон читает код?), Но он не указывает на фактический ход функции карты.

Как отобразить индикатор выполнения, который указывает, на каком этапе действует функция "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()

Любая помощь или предложения приветствуются...

Ответ 1

Найденное решение: будьте осторожны! Из-за многопроцессорности время оценки (итерация на цикл, общее время и т.д.) Может быть нестабильным, но индикатор выполнения работает отлично.

Примечание. Диспетчер контекста для пула доступен только в Python версии 3.3.

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()

Ответ 2

Используйте imap вместо 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__':
   with Pool(2) as p:
      r = list(tqdm.tqdm(p.imap(_foo, range(30)), total=30))

Ответ 3

основанный на ответе Хави Мартинеса, я написал функцию imap_unordered_bar. Его можно использовать так же, как imap_unordered с той лишь разницей, что отображается панель обработки.

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))

Ответ 4

Вы можете использовать вместо этого p_tqdm.

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)))

Ответ 5

Этот подход прост и работает.

from multiprocessing.pool import ThreadPool
import time
from tqdm import tqdm

def job():
    time.sleep(1)
    pbar.update()

pool = ThreadPool(5)
with tqdm(total=100) as pbar:
    for i in range(100):
        pool.apply_async(job)
    pool.close()
    pool.join()