如何在Python中通过多进程使用tqdm?

11

我正在尝试通过多进程使用 tqdm,但行为不如预期。我认为问题在于 pbar 的值没有在进程间更新。那么如何解决这个问题?我也尝试手动使用 Value 更新 pbar.n,但仍然失败。似乎 tqdm 不支持手动更新值和手动渲染。

def test(lock, pbar):
    for i in range(10000):
        sleep(0.1)
        lock.acquire()
        pbar.update()
        lock.release()

pbar = tqdm(total = 10000)
lock = Lock()
for i in range(5):
    Process(target = test, args = (lock, pbar))
1个回答

14

通常情况下,每个进程都有自己的数据,与其他进程无关。在Unix上调用os.fork时,在新进程中生成当前进程的副本。每个进程都获得所有全局值(例如pbar)的副本。每个进程的全局变量可能与其他进程中的变量共享相同的名称,但每个变量可以具有独立的值。

在您的情况下,您似乎希望只存在一个pbar,并且所有对update的调用都应该更新该pbar。因此,只在一个进程中创建pbar,并使用Queue向该进程发送信号以更新pbar

import multiprocessing as mp

SENTINEL = 1

def test(q):
    for i in range(10000):
        sleep(0.1)
        q.put(SENTINEL)

def listener(q):
    pbar = tqdm(total = 10000)
    for item in iter(q.get, None):
        pbar.update()

if __name__ == '__main__':
    q = mp.Queue()
    proc = mp.Process(target=listener, args=(q,))
    proc.start()
    workers = [mp.Process(target=test, args=(q,)) for i in range(5)]
    for worker in workers:
        worker.start()
    for worker in workers:
        worker.join()
    q.put(None)
    proc.join()

2
除了在 proc.join() 处永久阻塞外,它运行良好。我认为可以通过在 proc.join() 之前添加 q.put(None) 来结束监听器进程来解决这个问题。非常感谢。 - Sraw
1
@Sraw:哎呀,你说得很对。感谢指正。 - unutbu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接