2017-01-29 8 views
13

Чтобы сделать мой код более «pythonic» и быстрее, я использую «многопроцессорность» и функцию карты, чтобы отправить его: a) функцию и b) диапазон итераций.Многопроцессорность: используйте tqdm для отображения индикатора выполнения

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

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

Как отобразить индикатор, который указывает, на каком шаге функция «карта» является?

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

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

+0

Можете ли вы опубликовать фрагмент кода индикатора выполнения? – Alex

ответ

12

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

Примечание: менеджер контекста для бассейна доступен только начиная с версии 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() 
+0

'pbar.close()' не требуется, он будет автоматически закрыт при завершении 'with' –

+0

. Требуется ли здесь второй/внутренний вызов' tqdm'? – shadowtalker

+0

Как насчет вывода _foo (my_number), который возвращается как «r»? – Likak

12

Использование IMAP вместо карты, которая возвращает итератор обрабатываемых значений.

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

Я пробовал это решение. Он работал, но по какой-то причине необходим вызов 'list()', а также передача размера списка в аргументе 'total =' для 'tqdm()'. Почему это? –

+3

Оператор прилагаемого списка() ожидает завершения итератора. total = также требуется, так как tqdm не знает, как долго будет проходить итерация, – hkyi

+0

Есть ли аналогичное решение для 'starmap()'? – tarashypka

1

на основе ответа Хави Мартинеса я написал функцию 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))