为啥 Python 子进程“继承”父进程的线程?

Posted

技术标签:

【中文标题】为啥 Python 子进程“继承”父进程的线程?【英文标题】:Why does Python subprocess "inherit" the threads from the parent process?为什么 Python 子进程“继承”父进程的线程? 【发布时间】:2021-12-31 02:40:39 【问题描述】:

我是 Python 3 multiprocessing 模块的新手,可能似乎误解了其中的一个概念。在我的应用程序中,像往常一样,我有一个主线程,还有另一个用于一些“后台”工作的线程,称为“BgThread”。从第二个线程我生成了一个Process 并通过start() 运行它。

新的子进程现在可以正确启动并开始工作了。但是,当我在(VS Code)调试器中查看我的应用程序时,我可以看到这个子进程也运行着第二个线程,也称为“BgThread”。

在 Linux 上运行我尝试通过 mp.set_start_method("spawn") 生成线程,如多处理文档中所述,但结果相同。此外,当我在我的第二个线程类的run() 方法中设置断点时,在子进程中它不会在那里停止(但在主进程中它是正确的)。

这是正常行为吗?如果是这样,那么我不明白 - 为什么子进程也从其父进程继承第二个线程,即使它似乎并没有真正通过它再次启动它,如上所述?是否需要阻止我的子进程再次启动第二个线程?

【问题讨论】:

你屏蔽了if __name__ == "__main__":的多处理吗? 看起来调试器的行为不正确。我会尝试调查htop/top/ps @Timus 这是一个 Flask 应用程序,是的,我确实在其 run.py 文件中使用了 if 语句。我还定义了通过multiprocessing.set_start_method("spawn")生成子进程,而不是分叉它。 【参考方案1】:

正如@AndriiMaletskyi 评论的那样,您所看到的一定是您的调试器引入的一些奇怪结果。以下程序在 Linux 下运行,使用spawn 启动新进程,首先创建一个线程,然后启动一个进程。该线程被传递了一个multiprocessing.Value 实例,该实例在一个循环中递增5 次,在该循环中它还打印出一条消息。如果子进程继承了这个线程,我们希望看到打印出超过 5 条消息,并且这个 multiprocessing.Value 实例的最终值大于 5。此外,为了更好地衡量,子进程枚举了它的线程并且只有一个。如果它从主进程继承了线程,那么如果不是三个,那么至少会有两个。

from multiprocessing import Process, Value, set_start_method
from os import getpid
import threading
import time

def worker(*args):
    first_time = True
    for x, y in args:
        time.sleep(1.1)
        print(f'x + y = x + y')
        if first_time:
            first_time = False
            for thread in threading.enumerate():
                print('thread:', thread.name)

def my_thread(v):
    for counter in range(1, 6):
        print(f'time: time.time(), counter: counter, process id: getpid(), thread id: threading.get_ident()')
        with v.get_lock():
            v.value += 1
        time.sleep(1)

if __name__ == '__main__':
    set_start_method("spawn")
    v = Value('i', 0, lock=True)
    t = threading.Thread(target=my_thread, args=(v,))
    t.start()
    args = ((1, 2), (3, 4), (4, 5), (6,7))
    p = Process(target=worker, args=args)
    p.start()
    p.join()
    t.join()
    print('Value =', v.value)

打印:

time: 1637499015.9222672, counter: 1, process id: 33, thread id: 139689716135680
time: 1637499016.9244416, counter: 2, process id: 33, thread id: 139689716135680
1 + 2 = 3
thread: MainThread
time: 1637499017.925643, counter: 3, process id: 33, thread id: 139689716135680
3 + 4 = 7
time: 1637499018.926832, counter: 4, process id: 33, thread id: 139689716135680
4 + 5 = 9
time: 1637499019.9280066, counter: 5, process id: 33, thread id: 139689716135680
6 + 7 = 13
Value = 5

【讨论】:

以上是关于为啥 Python 子进程“继承”父进程的线程?的主要内容,如果未能解决你的问题,请参考以下文章

什么是子进程和父进程

Python3 多进程和多线程

python threading父进程不死,子线程不退出..如何才能使用完线程后回收线程?

python多进程和多线程

python -- 进程线程专题

为啥Node父进程使用子进程on message事件来处理子进程发送的消息