如何在多进程中杀掉所有的池工作线程?

11

我希望能够从一个单一的工作线程中停止所有线程。

我有一个包含10个工作线程的线程池:

def myfunction(i):
    print(i) 
    if (i == 20):
        sys.exit()

p = multiprocessing.Pool(10, init_worker) 

for i in range(100):
    p.apply_async(myfunction, (i,))

我的程序不会停止,其他进程会一直工作,直到完成所有100个迭代。 我希望能够从调用 sys.exit() 的线程内完全停止线程池。目前的编写方式只会停止调用 sys.exit() 的 worker。

2个回答

17

你的意图并不能达成,因为在工作进程中调用sys.exit()只会终止该工作进程。它对父进程或其他工作进程没有影响,因为它们是独立的进程,而引发SystemExit只会影响当前进程。你需要向父进程发送信号,告诉它应该关闭。对于你的使用情况,一种方法是使用在multiprocessing.Manager服务器中创建的Event

import multiprocessing

def myfunction(i, event):
    if not event.is_set():
        print i 
    if i == 20:
        event.set()

if __name__ == "__main__":
    p= multiprocessing.Pool(10) 
    m = multiprocessing.Manager()
    event = m.Event()
    for i in range(100):
        p.apply_async(myfunction , (i, event))
    p.close()

    event.wait()  # We'll block here until a worker calls `event.set()`
    p.terminate() # Terminate all processes in the Pool

输出:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

正如Luke的回答中所指出的,这里存在一种竞争关系:不能保证所有的工作者按顺序运行,因此可能会出现例如先运行myfunction(20, ..)再运行myfuntion(19, ..)的情况。此外,在主进程处理被设置的事件之前,20之后的其他工作者可能会先运行。我通过在打印i之前添加了if not event.is_set():的调用来减小了竞争窗口的大小,但它仍然存在。


@RajanChaudan 打错字了!我已经修复了。 - dano

1

你不能这样做。

即使在 i == 20 时能够结束所有进程,也无法确定只有20个数字被打印,因为进程将以非确定性顺序执行。

如果您想仅运行20个进程,则需要从主进程(即控制循环)中进行管理。


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