返回信息流在如下代码中,为什么主进程中的非daemon线程可以让主进程不退出(即执行main1()的代码,工作起来和预想的一样),而fork出来的Subprocess在执行完Sub的__init__之后就变成zombie了,非daemon线程并没有持续运行(即执行main()的代码,和预想的完全不同)。
```
import threading
import multiprocessing
import time
class Sub:
def __init__(self):
self.t = threading.Thread(target=self.is_alive, daemon=False)
self.t.start()
def is_alive(self):
while True:
print('Still alive')
time.sleep(1.0)
def main():
sub = multiprocessing.Process(target=Sub, daemon=False)
sub.start()
while True:
time.sleep(1)
def main1():
_ = Sub()
if __name__ == '__main__':
#main()
main1()
```
这是一条镜像帖。来源:北邮人论坛 / python / #23119同步于 2018/11/6
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Python机器人发帖
【问题】关于Python的multiprocessing的奇怪问题
Zelda
2018/11/6镜像同步11 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
我觉得是您没有理解daemon线程,主线程结束后非daemon不会结束。您自己跑一下我这段代码的main1()就明白了。
> A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left.
【 在 specops 的大作中提到: 】
: 1. 主线程执行完毕其他线程会一起结束
: 2. 子进程结束后父进程没有wait会变成zombie
> The parent process uses os.fork() to fork the Python interpreter. The child process, when it begins, is effectively identical to the parent process. All resources of the parent are inherited by the child process. * Note that safely forking a multithreaded process is problematic. *
Available on Unix only. The default on Unix.
【 在 Zelda (Zelda) 的大作中提到: 】
: 我觉得是您没有理解daemon线程,主线程结束后非daemon不会结束。您自己跑一下我这段代码的main1()就明白了。
: [md]
: > A thread can be flagged as a “daemon thread”. The significance of this flag is...
: ...................
多线程时:子线程设置daemon为True,则主线程结束后不等待子线程就退出。子线程设置daemon为False,则主线程需要等待子线程结束后退出。
这段引用依然没有解释我的问题啊。我的问题的本质是,“为什么daemon thread的特性在主进程里有用,到了子进程里就没用了”。
ps. 我并没有fork一个multithreaded process,而是fork了之后在子进程里启动了新的线程。
pps. 我不知道它所谓的UNIX是指狭义的UNIX还是包括Linux在内的其它POSIX,反正我的问题实在Linux下观测到的。
ppps. 其实问题很好解决,像下面这么写就没问题了。不过我觉得问题原因只有看了Python的daemon特性相关的代码才能了解了。
```
import threading
import multiprocessing
import time
class Sub:
def __init__(self):
self.t = threading.Thread(target=self.is_alive, daemon=False)
#self.t.start()
def __call__(self):
self.t.start()
self.t.join()
def is_alive(self):
while True:
print('Still alive')
time.sleep(1.0)
def main():
sub = multiprocessing.Process(target=Sub, daemon=False)
sub.start()
while True:
time.sleep(1)
def main1():
_ = Sub()
def main2():
sub = multiprocessing.Process(target=Sub())
sub.start()
while True:
time.sleep(1)
if __name__ == '__main__':
#main()
#main1()
main2()
```
【 在 specops 的大作中提到: 】
: [md]
: > The parent process uses os.fork() to fork the Python interpreter. The child process, when it begins, is effectively identical to the parent process. All resources of the parent are inherited by the child process. * Note that safely forking a multithreaded process is problematic. *
: Available on Unix only. The default on Unix.
: ...................
您没有理解我的问题,您不妨仔细看看我的描述。我很清楚daemon是干嘛的。
【 在 chenxiansf 的大作中提到: 】
: 多线程时:子线程设置daemon为True,则主线程结束后不等待子线程就退出。子线程设置daemon为False,则主线程需要等待子线程结束后退出。
首先你要知道daemon thread只是Python的“语法糖”,Unix并没有这个概念。再考虑这个“语法糖”是怎么实现的,如果我没记错是用的atexit,你可以翻源码确认一下。
如果上述内容成立,那么这个问题其实很简单,就是fork的过程中因为种种原因没有正确处理threading模块的初始化/清理工作,所以文档上写fork不要和多线程一起使用。
解决方案也很简单,把fork换成spawn就可以了。实际上你的main2和你的问题无关,你之前程序的__init__最后加上self.t.join()理论上也能正常跑,它给主线程续命了。
PS:UNIX是一类操作系统,Linux是其中之一
【 在 Zelda 的大作中提到: 】
: 这段引用依然没有解释我的问题啊。我的问题的本质是,“为什么daemon thread的特性在主进程里有用,到了子进程里就没用了”。
: ps. 我并没有fork一个multithreaded process,而是fork了之后在子进程里启动了新的线程。
: pps. 我不知道它所谓的UNIX是指狭义的UNIX还是包括Linux在内的其它POSIX,反正我的问题实在Linux下观测到的。
: ...................
您说对了。这段代码什么都不改在Windows上就是正常的,在Linux下加上multiprocessing.set_start_method('spawn')也没有问题了。
非常感谢。
【 在 specops 的大作中提到: 】
: 首先你要知道daemon thread只是Python的“语法糖”,Unix并没有这个概念。再考虑这个“语法糖”是怎么实现的,如果我没记错是用的atexit,你可以翻源码确认一下。
: 如果上述内容成立,那么这个问题其实很简单,就是fork的过程中因为种种原因没有正确处理threading模块的初始化/清理工作,所以文档上写fork不要和多线程一起使用。
: 解决方案也很简单,把fork换成spawn就可以了。实际上你的main2和你的问题无关,你之前程序的__init__最后加上self.t.join()理论上也能正常跑,它给主线程续命了。
: ...................