为什么 Python 子进程 "inherit" 来自父进程的线程?
Why does Python subprocess "inherit" the threads from the parent process?
我是 Python 3 multiprocessing
模块的新手,可能似乎误解了其中一个概念。在我的应用程序中,我像往常一样有主线程,还有另一个线程用于一些“后台”工作,称为“BgThread”。在第二个线程中,我通过 start()
.
生成了 Process
和 运行
新的子进程现在可以正确启动并执行其工作。但是,当我在 (VS Code) 调试器中查看我的应用程序时,我可以看到该子进程也有第二个线程 运行ning,再次称为“BgThread”。
运行 on Linux 我尝试通过 mp.set_start_method("spawn")
生成线程,如多处理文档中所述,但结果相同。此外,当我在第二个线程 class 的 run()
方法中设置断点时,在子进程中它不会停在那里(但它在主进程中这样做是正确的)。
这是正常行为吗?如果是这样,那么我不明白 - 为什么子进程也从其父进程继承这个第二个线程,即使它似乎并没有像上面描述的那样真正再次启动它?是否需要阻止我的子进程再次启动第二个线程?
正如@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 3 multiprocessing
模块的新手,可能似乎误解了其中一个概念。在我的应用程序中,我像往常一样有主线程,还有另一个线程用于一些“后台”工作,称为“BgThread”。在第二个线程中,我通过 start()
.
Process
和 运行
新的子进程现在可以正确启动并执行其工作。但是,当我在 (VS Code) 调试器中查看我的应用程序时,我可以看到该子进程也有第二个线程 运行ning,再次称为“BgThread”。
运行 on Linux 我尝试通过 mp.set_start_method("spawn")
生成线程,如多处理文档中所述,但结果相同。此外,当我在第二个线程 class 的 run()
方法中设置断点时,在子进程中它不会停在那里(但它在主进程中这样做是正确的)。
这是正常行为吗?如果是这样,那么我不明白 - 为什么子进程也从其父进程继承这个第二个线程,即使它似乎并没有像上面描述的那样真正再次启动它?是否需要阻止我的子进程再次启动第二个线程?
正如@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