다중 처리 : tqdm을 사용하여 진행률 표시 줄 표시


103

내 코드를보다 "pythonic"하고 빠르게 만들기 위해 "multiprocessing"과 맵 함수를 사용하여 a) 함수 및 b) 반복 범위를 보냅니다.

이식 된 솔루션 (즉, tqdm.tqdm (range (0, 30)) 범위에서 직접 tqdm 호출)은 다중 처리 (아래 코드에서 공식화 됨)에서 작동하지 않습니다.

진행률 표시 줄은 0 ~ 100 % (python이 코드를 읽을 때?)로 표시되지만지도 기능의 실제 진행률을 나타내지는 않습니다.

'지도'기능이 어느 단계에 있는지 나타내는 진행률 표시 줄을 표시하는 방법은 무엇입니까?

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

모든 도움이나 제안을 환영합니다 ...


진행률 표시 줄의 코드 조각을 게시 할 수 있습니까?
Alex

2
다음을 사용하여 솔루션을 찾는 사람들을 위해 .starmap(): 다음Pool추가 용 패치 .istarmap()입니다 tqdm.
Darkonaut

답변:


136

처리 된 값의 반복자를 반환하는 map 대신 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))

14
둘러싸는 list () 문은 반복기가 끝날 때까지 기다립니다. total =도 필요합니다. tqdm은 반복이 얼마나 오래
걸릴지 모르기

15
에 대한 유사한 솔루션이 starmap()있습니까?
tarashypka

2
for i in tqdm.tqdm(...): pass 더 간단 할 수 있습니다.list(tqdm.tqdm)
savfod

1
이것은 작동하지만 다른 사람이 각 반복마다 줄 바꿈에 진행률 표시 줄을 계속 인쇄 했습니까?
Dennis Subachev

3
동작은 언제 특정 유선된다 chunk_sizep.imap. tqdm모든 청크 대신 모든 반복을 업데이트 할 수 있습니까 ?
huangbiubiu

54

솔루션을 찾았습니다 : 조심하세요! 다중 처리로 인해 추정 시간 (루프 당 반복, 총 시간 등)이 불안정 할 수 있지만 진행률 표시 줄은 완벽하게 작동합니다.

참고 : 풀용 컨텍스트 관리자는 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 enumerate(p.imap_unordered(_foo, range(0, max_))):
                pbar.update()

2
pbar.close()필요하지 않습니다. 종료시 자동으로 닫힙니다with
Sagar Kar

5
여기에 두 번째 / 내부 tqdm전화가 필요합니까?
shadowtalker

7
문제의 "r"로 반환되는 _foo (my_number)의 출력은 어떻습니까?
Likak

3
에 대한 유사한 솔루션이 starmap()있습니까?
tarashypka

2
@shadowtalker-;)없이 작동하는 것 같습니다. 어쨌든- imap_unordered여기서 핵심은 최고의 성능과 최고의 진행률 막대 추정치를 제공합니다.
Tomasz Gandor

21

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

1
이것은 매우 잘 작동하며 pip install. 이것은 나의 대부분의 필요를 위해 tqdm을 대체하고 있습니다
crypdick

Merci Victor;)
Gabriel Romon 19

p_tqdm로 제한되며 multiprocessing.Pool스레드에 사용할 수 없음
pateheo

19

늦어서 죄송 합니다만 동시지도 만 있으면 최신 버전 ( tqdm>=4.42.0)에 다음이 내장되어 있습니다.

from tqdm.contrib.concurrent import process_map  # or thread_map
import time

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

if __name__ == '__main__':
   r = process_map(_foo, range(0, 30), max_workers=2)

참조 : https://tqdm.github.io/docs/contrib.concurrent/https://github.com/tqdm/tqdm/blob/master/examples/parallel_bars.py


1
감사합니다. 내가 시도한 다른 솔루션보다 훨씬 쉽게 작동합니다.
user3340499

쿨 (+1),하지만 HBox(children=(FloatProgress(value=0.0, max=30.0), HTML(value='')))Jupyter에서 던졌습니다
Ébe Isaac


tqdm_notebook을 해킹하기위한 토론에 문제가 있지만 tqdm.contrib.concurrent를 해결하기위한 솔루션을 사용할 수 없습니다.
Ébe Isaac

8

Xavi Martínez의 답변을 바탕으로 함수를 작성했습니다 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))

3
이렇게하면 새 줄의 각 단계에서 막대가 다시 그려집니다. 같은 줄을 어떻게 업데이트하나요?
misantroop

필자의 경우 솔루션 (Windows / Powershell) : Colorama.
misantroop

사가르는 @ scipy의 대답에 만든 주석처럼 'pbar.close ()는 필요하지, 그것은과 종료에 자동으로 종료됩니다'
테자스 셰티

1

병렬 실행 함수에서 결과를 다시 가져와야 할 때에 대한 필자의 견해입니다. 이 기능은 몇 가지 작업을 수행하지만 (더 자세히 설명하는 다른 게시물이 있음) 핵심은 대기중인 작업 대기열과 완료된 작업 대기열이 있다는 것입니다. 작업자가 대기중인 대기열의 각 작업을 완료하면 작업 완료 대기열에 결과를 추가합니다. tqdm 진행률 표시 줄을 사용하여 작업 완료 대기열에 검사를 래핑 할 수 있습니다. 여기에 do_work () 함수의 구현을 넣는 것이 아닙니다. 여기에있는 메시지는 작업 완료 대기열을 모니터링하고 결과가 나올 때마다 진행률 표시 줄을 업데이트하는 것이므로 관련이 없습니다.

def par_proc(job_list, num_cpus=None, verbose=False):

# Get the number of cores
if not num_cpus:
    num_cpus = psutil.cpu_count(logical=False)

print('* Parallel processing')
print('* Running on {} cores'.format(num_cpus))

# Set-up the queues for sending and receiving data to/from the workers
tasks_pending = mp.Queue()
tasks_completed = mp.Queue()

# Gather processes and results here
processes = []
results = []

# Count tasks
num_tasks = 0

# Add the tasks to the queue
for job in job_list:
    for task in job['tasks']:
        expanded_job = {}
        num_tasks = num_tasks + 1
        expanded_job.update({'func': pickle.dumps(job['func'])})
        expanded_job.update({'task': task})
        tasks_pending.put(expanded_job)

# Set the number of workers here
num_workers = min(num_cpus, num_tasks)

# We need as many sentinels as there are worker processes so that ALL processes exit when there is no more
# work left to be done.
for c in range(num_workers):
    tasks_pending.put(SENTINEL)

print('* Number of tasks: {}'.format(num_tasks))

# Set-up and start the workers
for c in range(num_workers):
    p = mp.Process(target=do_work, args=(tasks_pending, tasks_completed, verbose))
    p.name = 'worker' + str(c)
    processes.append(p)
    p.start()

# Gather the results
completed_tasks_counter = 0

with tqdm(total=num_tasks) as bar:
    while completed_tasks_counter < num_tasks:
        results.append(tasks_completed.get())
        completed_tasks_counter = completed_tasks_counter + 1
        bar.update(completed_tasks_counter)

for p in processes:
    p.join()

return results

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

-2

이 접근 방식은 간단하며 작동합니다.

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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.