Python 多进程池 信号

2 投票
1 回答
2468 浏览
提问于 2025-04-18 16:57

我遇到了一个小问题,我是Python中多进程模块的初学者,我需要创建一个可以随时通过SIGINT信号停止的进程池。

from multiprocessing import Pool, current_process
import signal
import time
import os

class Processor(object):
    def __init__(self, stack):
        self.stack = stack
        self.pool = Pool(processes=4, maxtasksperchild=1, initializer=self._init)

    def _init(self):
        cp = current_process()
        cp.daemon = False

    def launch(self):
        self.result = self.pool.map(func, self.stack)
        self.pool.close()
        self.pool.join()

def func(j):
    a, b = j
    time.sleep(1)
    return a * b

def breaker(*args):
    p.pool.terminate()
    p.pool.join()

def main():
    a = 4, 9
    b = 5, 7
    lst = [a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b]
    global p
    p = Processor(lst)
    signal.signal(signal.SIGINT, breaker)
    p.launch()
    ret = p.result
    for i in ret:
        print i

if __name__ == '__main__':
    print os.getpid()
    main()

没有任何信号的时候,代码运行得很好,但当我给这个进程发送信号时,它就不再工作了,停止的函数也从来没有被调用过。如果有人知道为什么,请告诉我。

1 个回答

0

当你调用了breaker函数时,它确实会被执行,但它并不会告诉主程序要退出。如果你在最后加上:

sys.exit(os.EX_OK)

或者在breaker的最后加上其他的退出指令,这样程序就会真正退出。

另外,你可能想把这个:

signal.signal(signal.SIGINT, breaker)

放在Pool定义之前,这样可以防止在子进程中出现未处理的键盘中断。

如果你想获取部分结果,可以尝试以下方法...

你的启动代码需要改成:

# start the workers
for el in self.stack:
    self.result[el] = self.pool.apply_async(func, (el, ), callback=your_callback)

#wait for results
for work in self.result.items(): # or iteritems if you're on pre python3
    work[1].get()

self.pool.close()
self.pool.join()

这样做会让结果一个一个地以异步调用的方式返回,你的回调函数就有机会把结果保存到某个地方,以便后续使用。

而使用map的话,它只会在最后一次调用时返回结果,所以你无法获取到部分结果。

接下来,你需要在某个地方定义your_callback,这样它就能把结果写入到一个全局的结果列表中:

def your_callback(result):
    global_list.append(result)

不过,结果的顺序可能会有些乱...

现在你的结果会一个一个地存放在global_list中,你可以在main()或者breaker()中输出这些结果。

撰写回答