Python多处理/线程化代码提前退出

问题描述

我正在尝试创建多个进程,每个进程都调用多个线程。 我正在使用python3.5运行以下代码

该问题的简化示例如下:

import multiprocessing
import time
import threading    

class dumb(threading.Thread):
    def __init__(self):
        super(dumb, self).__init__()
    def run(self):
        while True:
            print("hi")
            time.sleep(1)    

def test():
    for i in range(2):
        bar = dumb()
        bar.start()
def main():
    p = []
    for i in range(2):
        p.append(multiprocessing.Process(target=test))
    for i in p:
        i.start()
    for i in p:
        i.join()
if __name__ == '__main__':
    main()

我希望这段代码永远打印"hi",但它只为每个进程中的每个线程打印一次(总共打印4次)。

当我删除多进程时,多线程工作。

当我删除多线程时,多处理工作。

阅读多处理文档后,我认为问题所在的部分: Join的文档声明:"阻塞调用线程,直到其Join()方法被调用的进程终止,或者直到发生可选的超时。"

如果它如我所期望的那样工作,当尝试加入时,Main将永远等待。

我在WHILE循环周围放置了TRY/EXCEPT块,没有看到任何错误。

我尝试向"哑巴"类传递一个队列并传递异常,但队列仍然是空的。

任何有关如何调试它的提示都将不胜感激。我最好的猜测是

  • 线程提前退出(尽管While循环后的打印语句从未命中)

  • 主要退出并终止进程

  • 联接工作正常,但不是我预期的方式?

有什么想法吗?


解决方案

解决方法:新错误已作为http://bugs.python.org/issue18966的副本关闭

唉,没有简单、令人满意的"为什么"的解释。原因是multiprocessing通过调用os._exit()而不是正常的sys.exit()来安排工作进程离开Python。os._exit()跳过所有"正常"关机处理。跳过的部分是.join()-非守护进程线程,因此该进程在线程仍在运行时消失。

这至少(根据我的说法)应该被记录下来,或者最好是改变。

同时,您已经知道,解决方法是自己显式.join()线程。

另一种方式

在Python3.4或更高版本下,您也可以使用multiprocessingspawn的启动方法:

https://docs.python.org/3/library/multiprocessing.html?highlight=spawn#contexts-and-start-methods

这会导致工作进程通过sys.exit(exitcode)完成,它执行所有正常的关闭处理(包括.join()运行非后台进程线程)。

spawn是Windows上唯一可用的Start方法,这解释了为什么我在运行您的原始示例时没有问题。

相关文章