显示进度条以运行python脚本

时间:2019-08-23 15:54:21

标签: python pandas time

当我运行一个长的python程序时,我想显示一个进度条。我在线研究,发现下面的功能。

import sys, time

def progress(count, total, status=''):
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)

    sys.stdout.write('\r[%s] %s%s ...%s\r' % (bar, percents, '%', status))
    sys.stdout.flush()  

然后,我执行了以下操作:

total = 1000
i = 0
while i < total:
    progress(i, total, status='Doing very long job')
    # My long python program here   
    i += 1

当我尝试上述操作时,运行我的python程序会花费更长的时间。以上是使用progress函数并显示进度条的正确方法吗?感谢您的投入。

4 个答案:

答案 0 :(得分:1)

执行中花费的额外时间归因于频繁(1000x)控制台刷新。 请阅读以下问题:Why is printing to stdout so slow? Can it be sped up?

为解决此问题,我建议打印状态并每隔例如10或20次迭代:

total = 1000
i = 0
while i < total:
    if i % 20 == 0:
        progress(i, total, status='Doing very long job')
    # My long python program here   
    i += 1

但是,最好的方法是使用现有的库,例如tqdm(https://github.com/tqdm/tqdm)。它经过了优化,并提供了很酷的功能,例如嵌套的进度条。

答案 1 :(得分:0)

如果第三方库可以,我建议使用tqdm。另外,在询问性能时,如果您报告时间安排也会很有帮助。

提高性能的一种方法是不对循环的每次迭代都调用进度。 IO很昂贵,因此不断打印到屏幕上确实会使程序陷入瘫痪,尤其是如果您通过使用flush绕过缓冲。

答案 2 :(得分:0)

我编写了一个简单的进度条代码来显示类似这样的内容:

[############# 4 ------] 67.00%

要与FOR或WHILE一起放置,但您需要知道总大小:

class Progresso:
def __init__(self, total, steps):

    assert steps < 101 and type(total) == int and type(steps) == int and total > steps

    self.count = 0
    self.total = total
    self.steps = steps
    self.passo = total // steps
    if total < steps *10:
        self.test = 1
    else:
        self.test = total // (steps * 10)
        print(self.prog(), end='\r')

def printa(self):
    self.count += 1
    if self.count % self.test == 0:
        print(self.prog(), end='\r')


def prog(self):
    passado = self.count // self.passo
    fut = self.steps - passado + 1
    resto = int((self.count % self.passo) / self.passo * 10)
    if resto == 0:
        centro = '-'*(fut -1)
    else:
        centro = str(resto) + '-'*(fut-2)
    return '['+'#'*passado + centro + '] ' +'{:.2f}%     '.format(self.count/self.total*100)


def fim(self):
    self.count = self.total
    print(self.prog())

您像这样在FOR / WHILE之前开始:

p = Progresso(200000, 20)

在FOR / WHILE内插入 p.printa(),然后在FOR / WHILE后插入 p.fim()

答案 3 :(得分:0)

对进度功能进行相当简单的更改,通过将先前打印的条保存在函数属性中(请参见https://www.python.org/dev/peps/pep-0232/),可以确保仅在进度条已更改时才打印和刷新(见{{3}}):

import sys, time

def progress(count, total, status=''):
    # make sure the saved bar is initialized
    if not hasattr(progress,'lastbar'):
        progress.lastbar = ""
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)
    # only print the bar if it is different from the previous bar
    if bar != progress.lastbar:
        sys.stdout.write('\r[%s] %s%s ...%s\r' % (bar, percents, '%', status))
        sys.stdout.flush()  
        progress.lastbar = bar

total = 1000
i = 0
while i < total:
    progress(i, total, status='Doing very long job')
    # My long python program here   
    i += 1

上面的代码仅在条形本身已更改时打印和刷新-因此是60次而不是1000次-忽略了所显示的百分比和状态消息的更改-如果这些对您来说很重要,则您可能希望存储和比较完整的像这样的打印行(但这将执行更多的打印和更多的冲洗操作):

import sys, time

def progress(count, total, status=''):
    if not hasattr(progress,'lastbar'):
        progress.lastbar = ""
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)
    fullbar = '\r[%s] %s%s ...%s\r' % (bar, percents, '%', status)
    if fullbar != progress.lastbar:
        sys.stdout.write(fullbar)
        sys.stdout.flush()  
        progress.lastbar = fullbar

total = 1000
i = 0
while i < total:
    progress(i, total, status='Doing very long job')
    # My long python program here   
    i += 1

我敢肯定,也可以使用更复杂的方法在进度函数中构建“ 20分之一”逻辑。

建立进度条也可能是进度功能中昂贵的一部分-您可以通过将filled_len与先前的filled_len进行比较来避免输出不变时避免这种情况,并且不要如果值没有改变,甚至不会构建条形字符串,如下所示:

import sys, time

def progress(count, total, status=''):
    if not hasattr(progress,'lastlen'):
        progress.lastlen = 0
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))
    if filled_len != progress.lastlen:
        percents = round(100.0 * count / float(total), 1)
        bar = '=' * filled_len + '-' * (bar_len - filled_len)
        fullbar = '\r[%s] %s%s ...%s\r' % (bar, percents, '%', status)
        sys.stdout.write(fullbar)
        sys.stdout.flush()  
        progress.lastlen = filled_len

total = 1000
i = 0
while i < total:
    progress(i, total, status='Doing very long job')
    # My long python program here   
    i += 1