Python 多处理 - 了解每个进程进度的最佳方式

标签 python multiprocessing progress-bar

我想知道我的流程的进度。目前我使用的不是很有效。这是一个mwe:

import time
from multiprocessing import Pool as ProcessPool
import progressbar
import random

def some_random_calculation(n):
    with progressbar.ProgressBar(max_value=n) as bar:
        for i in range(0,n):
            time.sleep(1)
            bar.update(i)

if __name__=='__main__':

    arguments = [random.randint(4,10) for i in range(4)]

    pool = ProcessPool(4)
    results = pool.map_async(some_random_calculation, arguments)
    print(results.get())
    pool.close() 
    pool.join()

在本例中,我使用的是 progressbar2,但是,当进程超过 1 时,输出会在同一行上不断更新:

从图中可以看出,条形图是按排序顺序排列的,因为在第一个条形图结束后,其他进程会创建一个新的条形图。当有多个进程时,单个条在同一行上更新。

我正在寻找解决我的问题的方法,动态更新 n 条会很酷。但是,可能有一种更聪明的方法来了解不同流程的进度。有什么建议吗?

最佳答案

所以这到目前为止还不完美,如果您想把一切都弄好的话,这个主题相当复杂。但有一件事是肯定的,您应该从子流程外部监控进度。

最快也可能是最简单的方法是拥有一个返回状态的调用函数,并且外部的调控器可以让用户了解最新的进度。这看起来像这样:

import os, signal
from threading import Thread, enumerate as t_enumerate
from time import time, sleep
from random import random

clear = lambda: os.system('cls' if os.name=='nt' else 'clear')

def sig_handler(signal, frame):
    for t in t_enumerate():
        if t.getName() != 'MainThread':
            t.stop()
    exit(0)
signal.signal(signal.SIGINT, sig_handler)

class worker(Thread):
    def __init__(self, init_value=0):
        Thread.__init__(self)
        self.init_value = init_value
        self.progress = 0
        self.run_state = True
        self.start() # Start ourselves instead of from outside.

    def poll(self):
        return self.progress

    def stop(self):
        self.run_state = False

    def run(self):
        main_thread = None
        for t in t_enumerate():
            if t.getName() == 'MainThread':
                main_thread = t
                break

        while main_thread and self.run_state and main_thread.isAlive():
            for i in range(0, 100):
                self.init_value *= i
                self.progress = i
                sleep(random())
            break # Yea kinda unessecary while loop. meh..

workers = [worker(0) for i in range(4)]

while len(t_enumerate()) > 1:
    clear()
    for index, worker_handle in enumerate(workers):
        progress = worker_handle.poll()
        print(f'Thread {index} is at {progress}/100.')
    sleep(1)

另一种方法是让每个线程在打印前获取线程池的锁。但这增加了复杂性,对于初学者来说,他们都需要在打印时间时同步,这样他们就不会随意获取锁来打印,但你在其他部分正在打印其他内容的输出过程。否则它们会以错误的顺序打印,或者您需要跟踪应该回溯重写的行。

这里可能会有一位线程大师提供更好的答案,但这是我的两分钱。只需添加一个轮询函数,进行组合状态更新,并忍受调用每个线程所需的非常有限的处理能力。除非您有数千个,否则多次调用不会对性能产生任何影响。

关于Python 多处理 - 了解每个进程进度的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58238272/

相关文章:

python - QThread.isFinished 在连接到 finished() 信号的插槽中返回 False

c# - 创建在所有进程之间共享状态的多进程架构的最轻量级解决方案是什么

php - 如果图像标签是从数据库动态创建的,我如何使用 javascript 或 php 来确定何时加载图像?

android - 文件解压进度条

Python:BeautifulSoup - 从类的名称中获取属性值

python - 如何在 Python 中创建无限循环(不使用 while 循环)?

python - 在多索引 Python Panda 数据框中过滤多个项目

python - 运行多个python脚本和多处理有什么区别

python - Python 中的多处理 : web scraping doesn't speed up

Android ProgressDialog 进度条按正确的顺序做事