Индикатор Выполнения Python
Как я могу использовать индикатор выполнения, когда мой скрипт выполняет какую-то задачу, которая, вероятно, займет время?
например, функция, которая занимает некоторое время для завершения и возвращает True когда сделано. Как я могу отобразить индикатор выполнения во время выполнения функции?
обратите внимание, что мне нужно, чтобы это было в режиме реального времени, поэтому я не могу понять, что с этим делать. Мне нужен thread для этого? Я понятия не имею.
сейчас я ничего не печатаю в то время как функция выполняется, однако индикатор будет приятно. Также меня больше интересует, как это можно сделать с точки зрения кода.
21 ответов:
есть определенные библиотеки (вот так вот) но, может быть, что-то очень простое будет делать:
import time import sys toolbar_width = 40 # setup toolbar sys.stdout.write("[%s]" % (" " * toolbar_width)) sys.stdout.flush() sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '[' for i in xrange(toolbar_width): time.sleep(0.1) # do real work here # update the bar sys.stdout.write("-") sys.stdout.flush() sys.stdout.write("\n")Примечание: этот прогрессбар является вилкой progressbar который не поддерживался в течение многих лет.
С tqdm вы можете добавить индикатор прогресса в ваши петли в секунду:
In [20]: import time In [21]: from tqdm import tqdm In [23]: for i in tqdm(range(10)): ....: time.sleep(3) 60%|██████ | 6/10 [00:18<00:12, 0.33 it/s]
приведенные выше предложения довольно хороши, но я думаю, что большинство людей просто хотят готовое решение, без зависимости от внешних пакетов, но также многоразовое.
Я получил лучшие моменты из всех вышеперечисленных и превратил его в функцию вместе с тестовыми случаями.
чтобы использовать его, просто скопируйте строки в разделе "def update_progress(progress)", но не тестовый скрипт. Не забудьте импортировать sys. Вызывайте его всякий раз, когда вам нужно отобразить или обновить ход выполнения бар.
это работает путем прямой отправки символа "\r"в консоль для перемещения курсора обратно в начало. "print" в python не повторяет вышеприведенный символ для этой цели, поэтому нам нужен 'sys'
import time, sys # update_progress() : Displays or updates a console progress bar ## Accepts a float between 0 and 1. Any int will be converted to a float. ## A value under 0 represents a 'halt'. ## A value at 1 or bigger represents 100% def update_progress(progress): barLength = 10 # Modify this to change the length of the progress bar status = "" if isinstance(progress, int): progress = float(progress) if not isinstance(progress, float): progress = 0 status = "error: progress var must be float\r\n" if progress < 0: progress = 0 status = "Halt...\r\n" if progress >= 1: progress = 1 status = "Done...\r\n" block = int(round(barLength*progress)) text = "\rPercent: [{0}] {1}% {2}".format( "#"*block + "-"*(barLength-block), progress*100, status) sys.stdout.write(text) sys.stdout.flush() # update_progress test script print "progress : 'hello'" update_progress("hello") time.sleep(1) print "progress : 3" update_progress(3) time.sleep(1) print "progress : [23]" update_progress([23]) time.sleep(1) print "" print "progress : -10" update_progress(-10) time.sleep(2) print "" print "progress : 10" update_progress(10) time.sleep(2) print "" print "progress : 0->1" for i in range(100): time.sleep(0.1) update_progress(i/100.0) print "" print "Test completed" time.sleep(10)вот что показывает результат тестового сценария (последний индикатор выполнения анимируется):
progress : 'hello' Percent: [----------] 0% error: progress var must be float progress : 3 Percent: [##########] 100% Done... progress : [23] Percent: [----------] 0% error: progress var must be float progress : -10 Percent: [----------] 0% Halt... progress : 10 Percent: [##########] 100% Done... progress : 0->1 Percent: [##########] 99.0% Test completed
для подобного приложения (отслеживание прогресса в цикле) я просто использовал python-progressbar:
их пример идет примерно так,
from progressbar import * # just a simple progress bar widgets = ['Test: ', Percentage(), ' ', Bar(marker='0',left='[',right=']'), ' ', ETA(), ' ', FileTransferSpeed()] #see docs for other options pbar = ProgressBar(widgets=widgets, maxval=500) pbar.start() for i in range(100,500+1,50): # here do something long at each iteration pbar.update(i) #this adds a little symbol at each iteration pbar.finish() print
Я только что сделал простой класс прогресса для моих нужд после поиска здесь эквивалентного решения. Я подумал, что могу хорошо опубликовать его.
from __future__ import print_function import sys import re class ProgressBar(object): DEFAULT = 'Progress: %(bar)s %(percent)3d%%' FULL = '%(bar)s %(current)d/%(total)d (%(percent)3d%%) %(remaining)d to go' def __init__(self, total, width=40, fmt=DEFAULT, symbol='=', output=sys.stderr): assert len(symbol) == 1 self.total = total self.width = width self.symbol = symbol self.output = output self.fmt = re.sub(r'(?P<name>%\(.+?\))d', r'\g<name>%dd' % len(str(total)), fmt) self.current = 0 def __call__(self): percent = self.current / float(self.total) size = int(self.width * percent) remaining = self.total - self.current bar = '[' + self.symbol * size + ' ' * (self.width - size) + ']' args = { 'total': self.total, 'bar': bar, 'current': self.current, 'percent': percent * 100, 'remaining': remaining } print('\r' + self.fmt % args, file=self.output, end='') def done(self): self.current = self.total self() print('', file=self.output)
пример :
from time import sleep progress = ProgressBar(80, fmt=ProgressBar.FULL) for x in xrange(progress.total): progress.current += 1 progress() sleep(0.1) progress.done()напечатает следующее:
[======== ] 17/80 ( 21%) 63 to go
попробуйте прогресс от https://pypi.python.org/pypi/progress.
from progress.bar import Bar bar = Bar('Processing', max=20) for i in range(20): # Do some work bar.next() bar.finish()результат будет бар, как показано ниже:
Processing |############# | 42/100
мне нравится ответ Брайана Хуу для своей простоты и не нуждающихся во внешних пакетах. Я немного изменил его, поэтому я добавляю свою версию здесь:
import sys import time def updt(total, progress): """ Displays or updates a console progress bar. Original source: https://stackoverflow.com/a/15860757/1391441 """ barLength, status = 20, "" progress = float(progress) / float(total) if progress >= 1.: progress, status = 1, "\r\n" block = int(round(barLength * progress)) text = "\r[{}] {:.0f}% {}".format( "#" * block + "-" * (barLength - block), round(progress * 100, 0), status) sys.stdout.write(text) sys.stdout.flush() runs = 300 for run_num in range(runs): time.sleep(.1) updt(runs, run_num + 1)он принимает общее количество запусков (
total) и количество запусков, обработанных до сих пор (progress), полагаяtotal >= progress. Результат выглядит так:[#####---------------] 27%
мне очень нравится python-progressbar, так как он очень прост в использовании.
для самого простого случая, это просто:
import progressbar import time progress = progressbar.ProgressBar() for i in progress(range(80)): time.sleep(0.01)внешний вид можно настроить, и он может отображать расчетное оставшееся время. Для примера используем тот же код, что и выше, но с:
progress = progressbar.ProgressBar(widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage(), ' ', progressbar.ETA()])
многие из ответов выше полагаются на внешние пакеты, но я также думаю (как указано выше), что большинство людей просто хотят готовое решение. Приведенный ниже код может быть адаптирован в соответствии с вашими потребностями путем настройки Строковой части.
это проще и работает без необходимости второго потока для обновления панели. Некоторые пакеты делать. Второй поток может быть проблемой, например, для ноутбука ipython.
приведенный ниже код работает только с итераторами, которые укажите длину(т. е. len (итератор) должен быть определен).
import sys def progressbar(it, prefix="", size=60): count = len(it) def _show(_i): x = int(size*_i/count) sys.stdout.write("%s[%s%s] %i/%i\r" % (prefix, "#"*x, "."*(size-x), _i, count)) sys.stdout.flush() _show(0) for i, item in enumerate(it): yield item _show(i+1) sys.stdout.write("\n") sys.stdout.flush()пример:
import time for i in progressbar(range(15), "Computing: ", 40): time.sleep(0.1) # any calculation you needвыход:
Computing: [........................................] 0/15...
Computing: [########................................] 3/15...
Computing: [########################################] 15/15
itможет быть любой итерируемый объект сlen, например ['a', 'b',` c'] ' работает просто отлично.
мне это нравится страница.
начинается с простого примера и переходит на многопоточную версию. Работает из коробки. Нет 3-й партии пакетов не требуется.
код будет выглядеть примерно так:
import time import sys def do_task(): time.sleep(1) def example_1(n): for i in range(n): do_task() print '\b.', sys.stdout.flush() print ' Done!' print 'Starting ', example_1(10)или вот пример использования потоков для запуска вращающейся загрузочной панели во время работы программы:
import sys import time import threading class progress_bar_loading(threading.Thread): def run(self): global stop global kill print 'Loading.... ', sys.stdout.flush() i = 0 while stop != True: if (i%4) == 0: sys.stdout.write('\b/') elif (i%4) == 1: sys.stdout.write('\b-') elif (i%4) == 2: sys.stdout.write('\b\') elif (i%4) == 3: sys.stdout.write('\b|') sys.stdout.flush() time.sleep(0.2) i+=1 if kill == True: print '\b\b\b\b ABORT!', else: print '\b\b done!', kill = False stop = False p = progress_bar_loading() p.start() try: #anything you want to run. time.sleep(1) stop = True except KeyboardInterrupt or EOFError: kill = True stop = True
Если это большой цикл с фиксированным количеством итераций, что занимает много времени вы можете использовать эту функцию я сделал. Каждая итерация цикла добавляет прогресс. Где count-это текущая итерация цикла, total-это значение, которое вы зацикливаете, а size (int) - это то, насколько большой вы хотите бар с шагом 10 т. е. (размер 1 =10 символов, размер 2 =20 символов)
import sys def loadingBar(count,total,size): percent = float(count)/float(total)*100 sys.stdout.write("\r" + str(int(count)).rjust(3,'0')+"/"+str(int(total)).rjust(3,'0') + ' [' + '='*int(percent/10)*size + ' '*(10-int(percent/10))*size + ']')пример:
for i in range(0,100): loadingBar(i,100,2) #do some codeвыход:
i = 50 >> 050/100 [========== ]
Если ваша работа не может быть разбита на измеримые куски, вы можете вызвать свою функцию в новом потоке и время, сколько это займет:
import thread import time import sys def work(): time.sleep( 5 ) def locked_call( func, lock ): lock.acquire() func() lock.release() lock = thread.allocate_lock() thread.start_new_thread( locked_call, ( work, lock, ) ) # This part is icky... while( not lock.locked() ): time.sleep( 0.1 ) while( lock.locked() ): sys.stdout.write( "*" ) sys.stdout.flush() time.sleep( 1 ) print "\nWork Done"вы можете, очевидно, увеличить точность синхронизации по мере необходимости.
вот короткое решение, которое строит полоса загрузки программно (вы должны решить, как долго вы хотите его).
import time n = 33 # or however many loading slots you want to have load = 0.01 # artificial loading time! loading = '.' * n # for strings, * is the repeat operator for i in range(n+1): # this loop replaces each dot with a hash! print('\r%s Loading at %3d percent!' % (loading, i*100/n), end='') loading = loading[:i] + '#' + loading[i+1:] time.sleep(load)
Мне нравится Габриэль ответ, но я изменил его, чтобы быть гибким. Вы можете отправить bar-length в функцию и получить свой индикатор выполнения с любой длиной, которую вы хотите. И вы не можете иметь индикатор с нулевой или отрицательной длины. Кроме того, вы можете использовать эту функцию, как Габриэль ответ (Посмотрите на Пример №2).
import sys import time def ProgressBar(Total, Progress, BarLength=20, ProgressIcon="#", BarIcon="-"): try: # You can't have a progress bar with zero or negative length. if BarLength <1: BarLength = 20 # Use status variable for going to the next line after progress completion. Status = "" # Calcuting progress between 0 and 1 for percentage. Progress = float(Progress) / float(Total) # Doing this conditions at final progressing. if Progress >= 1.: Progress = 1 Status = "\r\n" # Going to the next line # Calculating how many places should be filled Block = int(round(BarLength * Progress)) # Show this Bar = "[{}] {:.0f}% {}".format(ProgressIcon * Block + BarIcon * (BarLength - Block), round(Progress * 100, 0), Status) return Bar except: return "ERROR" def ShowBar(Bar): sys.stdout.write(Bar) sys.stdout.flush() if __name__ == '__main__': print("This is a simple progress bar.\n") # Example #1: print('Example #1') Runs = 10 for i in range(Runs + 1): progressBar = "\rProgress: " + ProgressBar(10, i, Runs) ShowBar(progressBar) time.sleep(1) # Example #2: print('\nExample #2') Runs = 10 for i in range(Runs + 1): progressBar = "\rProgress: " + ProgressBar(10, i, 20, '|', '.') ShowBar(progressBar) time.sleep(1) print('\nDone.') # Example #2: Runs = 10 for i in range(Runs + 1): ProgressBar(10, i) time.sleep(1)результат:
Это простой индикатор выполнения.
Пример 1
прогресс: [###-------] 30%
Пример #2
прогресс: [||||||||||||........] 60%
сделано.
Попробуйте PyProg. PyProg-это библиотека с открытым исходным кодом для Python для создания супер настраиваемых индикаторов и баров прогресса.
В настоящее время он находится в версии 1.0.2; он размещен на Github и доступен на PyPI (ссылки ниже). Он совместим с Python 3 & 2, а также может использоваться с консолью Qt.
Он очень прост в использовании. Следующий код:
import pyprog from time import sleep # Create Object prog = pyprog.ProgressBar(" ", "", 34) # Update Progress Bar prog.update() for i in range(34): # Do something sleep(0.1) # Set current status prog.set_stat(i + 1) # Update Progress Bar again prog.update() # Make the Progress Bar final prog.end()будет:
Initial State: Progress: 0% -------------------------------------------------- When half done: Progress: 50% #########################------------------------- Final State: Progress: 100% ##################################################Я на самом деле сделал PyProg, потому что мне нужен был простой, но супер настраиваемая библиотека прогресс-бар. Вы можете легко установить его с:
pip install pyprog.PyProg Github:https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/
Это довольно просто в Python3:
import time import math def show_progress_bar(bar_length, completed, total): bar_length_unit_value = (total / bar_length) completed_bar_part = math.ceil(completed / bar_length_unit_value) progress = "*" * completed_bar_part remaining = " " * (bar_length - completed_bar_part) percent_done = "%.2f" % ((completed / total) * 100) print(f'[{progress}{remaining}] {percent_done}%', end='\r') bar_length = 30 total = 100 for i in range(0, total + 1): show_progress_bar(bar_length, i, total) time.sleep(0.1) print('\n')
приведенный ниже код является довольно общим решением, а также имеет время, прошедшее и оставшееся время оценки. Вы можете использовать любую итерацию с ним. Индикатор выполнения имеет фиксированный размер 25 символов, но он может отображать обновления с шагом 1%, используя символы полного, половины и четверти блока. Вывод выглядит так:
18% |████▌ | [0:00:01, 0:00:07]код, например:
import sys, time from numpy import linspace def ProgressBar(iterObj, refreshTime=10): #refreshTime=10: refresh the time estimate at least every 10 sec. def SecToStr(sec): m, s = divmod(sec, 60) h, m = divmod(m, 60) return u'%d:%02d:%02d'%(h,m,s) L = len(iterObj) steps = {int(x):y for x,y in zip(np.linspace(0,L, min(100,L),endpoint=False), np.linspace(0,100,min(100,L),endpoint=False))} qSteps = ['', u'\u258E',u'\u258C',u'\u258A'] # quarter and half block chars startT = endT = time.time() timeStr = ' [0:00:00, -:--:--]' for nn,item in enumerate(iterObj): if nn in steps: done = u'\u2588'*int(steps[nn]/4.0)+qSteps[int(steps[nn]%4)] todo = ' '*(25-len(done)) barStr = u'%4d%% |%s%s|'%(steps[nn], done, todo) if nn>0: endT = time.time() timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1))) sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush() elif time.time()-endT > refreshTime: endT = time.time() timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1))) sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush() yield item barStr = u'%4d%% |%s|'%(100, u'\u2588'*25) timeStr = ' [%s, 0:00:00]\n'%(SecToStr(time.time()-startT)) sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush() # Example s = '' for op in ProgressBar(list('Disassemble and reassemble this string')): time.sleep(0.5) s += op print sпредложения по улучшению или другие комментарии приветствуются. Повеселись.
вы должны связать индикатор выполнения с текущей задачей (чтобы он измерял прогресс :D). Например, если вы FTPing файл, вы можете сказать ftplib, чтобы захватить определенный размер буфера, скажем, 128K, а затем добавить в свой индикатор выполнения любой процент от размера файла 128k представляет. Если вы используете CLI, и ваш индикатор выполнения имеет длину 20 символов, вы добавите один символ, когда 1/20th файла будет передан.
@Massagran: он хорошо работает в моих программах. Кроме того, нам нужно добавить счетчик, чтобы указать время цикла. Этот счетчик играет в качестве аргумента метода
update. Например: прочитайте все строки тестового файла и обработайте их на чем-нибудь. Предположим, что функцияdosth()Не беспокойтесь в переменнойi.lines = open(sys.argv[1]).readlines() i = 0 widgets=[Percentage(), Bar()] pbar = ProgressBar(widgets=widgets,maxval=len(lines)).start() pbar.start() for line in lines:<pre> dosth(); i += 1 pbar.update(i)</pre> pbar.finish()переменная
iконтролирует состояниеpbarметодомupdate
вы также можете использовать просвети. Главное преимущество заключается в том, что вы можете войти в то же время без перезаписи индикатора выполнения.
import time import enlighten manager = enlighten.Manager() pbar = manager.counter(total=100) for num in range(1, 101): time.sleep(0.05) print('Step %d complete' % num) pbar.update()Он также обрабатывает несколько индикаторов выполнения.
import time import enlighten manager = enlighten.Manager() odds = manager.counter(total=50) evens = manager.counter(total=50) for num in range(1, 101): time.sleep(0.05) if num % 2: odds.update() else: evens.update()
Comments