Python: Run a progess bar and work simultaneously?

2020-03-26 04:21发布

问题:

I want to know how to run a progress bar and some other work simultaneously, then when the work is done, stop the progress bar in Python (2.7.x)

import sys, time
def progress_bar():
 while True:
  for c in ['-','\\','|','/']:
   sys.stdout.write('\r' + "Working " + c)
   sys.stdout.flush()
   time.sleep(0.2)

def work():
 *doing hard work*

How would I be able to do something like:

progress_bar() #run in background?
work()
*stop progress bar*
print "\nThe work is done!"

回答1:

You could run a thread in the background using the threading module. For example:

def run_progress_bar(finished_event):
    chars = itertools.cycle(r'-\|/')
    while not finished_event.is_set():
        sys.stdout.write('\rWorking ' + next(chars))
        sys.stdout.flush()
        finished_event.wait(0.2)


# somewhere else...
finished_event = threading.Event()
progress_bar_thread = threading.Thread(target=run_progress_bar, args=(finished_event,))
progress_bar_thread.start()
# do stuff
finished_event.set()
progress_bar_thread.join()


回答2:

You can create a separate thread that displays the progress bar. This could be done as shown in @icktoofay's answer, however I would prefer something like the following implementation which derives a new thread subclass for the task. One advantage to this approach is that everything is self contained in each instance of the new class so you don't need global variables for communications between them and the main thread.

import sys
import threading
import time

class ProgressBarThread(threading.Thread):
    def __init__(self, label='Working', delay=0.2):
        super(ProgressBarThread, self).__init__()
        self.label = label
        self.delay = delay  # interval between updates
        self.running = False
    def start(self):
        self.running = True
        super(ProgressBarThread, self).start()
    def run(self):
        label = '\r' + self.label + ' '
        while self.running:
            for c in ('-', '\\', '|', '/'):
                sys.stdout.write(label + c)
                sys.stdout.flush()
                time.sleep(self.delay)
    def stop(self):
        self.running = False
        self.join()  # wait for run() method to terminate
        sys.stdout.write('\r' + len(self.label)*' ' + '\r')  # clean-up
        sys.stdout.flush()

def work():
    time.sleep(5)  # *doing hard work*

pb_thread = ProgressBarThread('Computing')
pb_thread.start()
work()
pb_thread.stop()
print("The work is done!")