Индикатор Выполнения Python



Как я могу использовать индикатор выполнения, когда мой скрипт выполняет какую-то задачу, которая, вероятно, займет время?



например, функция, которая занимает некоторое время для завершения и возвращает True когда сделано. Как я могу отобразить индикатор выполнения во время выполнения функции?



обратите внимание, что мне нужно, чтобы это было в режиме реального времени, поэтому я не могу понять, что с этим делать. Мне нужен thread для этого? Я понятия не имею.



сейчас я ничего не печатаю в то время как функция выполняется, однако индикатор будет приятно. Также меня больше интересует, как это можно сделать с точки зрения кода.

1319   21  

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'] ' работает просто отлично.

использовать эту библиотеку: fish (GitHub).

использование:

>>> import fish
>>> while churning:
...     churn_churn()
...     fish.animate()

удачи!

мне это нравится страница.

начинается с простого примера и переходит на многопоточную версию. Работает из коробки. Нет 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

    Ничего не найдено.