Python线程:多线进度报告

时间:2015-01-21 00:03:45

标签: python multithreading progress-bar progress python-multithreading

我正在编写这个程序,它使用线程同时下载多个文件,并报告屏幕上每个文件的进度。 我正在使用一个不同的线程来下载每个文件。这没问题:

for file_url, filename in zip(file_urls, filenames):
    th = Thread(target=download_file, args=(file_url, filename))
    threads.append(th)
    th.start()

for thread in threads:
    thread.join()

问题是我不知道我可以在屏幕上打印每个文件进度报告,如下所示:

    "Downloading 'example1.zip':  54366 bytes of 2240799  70.7%" 
    "Downloading 'example2.zip':  31712 bytes of 1924639  64.7%" 
    "Downloading 'example3.zip':  21712 bytes of 3224979  34.7%" 

以下代码段用于单行进度报告:

def chunk_report(bytes_so_far, total_size, filename):

    percent = float(bytes_so_far) / total_size
    percent = round(percent * 100, 2)
    print "Downloading '{0}':  {1} of {2}  {3:3.2g}% \r".format(filename,
                                        bytes_so_far, total_size, percent),

,输出如下:

    "Downloading 'example2.zip':  31712 bytes of 1924639  64.7%" 

每次线程调用此函数时,它都会更新线程正在下载的文件的屏幕。

所以,问题是如何打印多线进度报告,就像我在python中说明的那样?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我会使用Queue向报告主题报告进度:

  1. 创建队列
  2. 生成每个下载线程,将队列作为参数传递
  3. 每次下载put进度消息到队列
  4. 生成一个报告线程,该线程从队列中读取进度消息并更新显示
  5. 模拟示例:

    import threading
    import time
    import random
    import Queue
    import sys
    
    # a downloading thread
    def worker(path, total, q):
      size = 0
      while size < total:
        dt = random.randint(1,3)
        time.sleep(dt)
        ds = random.randint(1,5)
        size = size + ds
        if size > total: size = total
        q.put(("update", path, total, size))
      q.put(("done", path))
    
    # the reporting thread
    def reporter(q, nworkers):
      status = {}
      while nworkers > 0:
        msg = q.get()
        if msg[0] == "update":
          path, total, size = msg[1:]
          status[path] = (total, size)
          # update the screen here
          show_progress(status)
        elif msg[0] == "done":
          nworkers = nworkers - 1
      print ""
    
    def show_progress(status):
      line = ""
      for path in status:
        (total, size) = status[path]
        line = line + "%s: %3d/%d   " % (path, size,total)
      sys.stdout.write("\r"+line)
      sys.stdout.flush()
    
    def main():
      q = Queue.Queue()
      w1 = threading.Thread(target = worker, args = ("abc", 30, q) )
      w2 = threading.Thread(target = worker, args = ("foobar", 25, q))
      w3 = threading.Thread(target = worker, args = ("bazquux", 16, q))
      r = threading.Thread(target = reporter, args = (q, 3))
      for t in [w1,w2,w3,r]: t.start()
      for t in [w1,w2,w3,r]: t.join()
    
    main()