Python子进程在主进程从stdin进行阻塞读取时被阻塞
我有一个用Python写的多进程应用程序,它通过多进程API启动“工作者”。这个主进程是由一个不是用Python写的服务进程启动的。工作者可能会使用subprocess.Popen
来启动其他非Python的子进程。
为了更清楚,这里是整个进程的层级结构:
- service.exe: 服务进程(本地可执行文件)
- python.exe: Python主进程(下面的程序)
- python.exe: Python子进程(由Process启动的任务函数)
- subprocess.exe: 本地子进程(见下面的解释)
- python.exe: Python子进程(由Process启动的任务函数)
- python.exe: Python主进程(下面的程序)
当服务进程停止时,它必须告诉Python进程退出。我是通过标准输入来实现这个的。这样做的好处是,如果服务进程崩溃或被杀掉,Python进程的标准输入就会关闭,这样它会退出,就不会留下孤儿进程。
import multiprocessing
import time
import sys
def task():
print("Task started...")
# TODO: Start a native process here using Subprocess.popen
time.sleep(3)
print("Task ended")
if __name__ == '__main__':
process = multiprocessing.Process(target=task)
process.start()
# time.sleep(3) # "workaround"
sys.stdin.read()
print("Terminating process...")
process.terminate()
但是,似乎当我添加sys.stdin.read()
时,Python子进程虽然启动了,但什么都不做。它看起来就像是卡住了一样。
一个(不好的)解决办法是,在读取标准输入之前加上time.sleep(3)
。这样,上面的程序就能正常工作了。不过,似乎由Python子进程启动的子进程仍然可能会被阻塞,而且只有在我在主进程中进行阻塞读取时,它们才会被阻塞。
这个问题并不是在所有系统上都会出现。我在一台Windows 8的机器上观察到了这个问题,而在另一台Windows机器上则从未发生过。我使用的是Python 2.7.2。
我的问题是:主进程中的阻塞读取怎么会影响子进程?难道子进程不应该独立于主进程的操作而启动和运行吗?(我只是想理解这个问题。如果你能找到一个更好的方法来让服务进程停止Python进程,我会很感激,但这个奇怪的阻塞行为让我很困扰。)
1 个回答
你的子进程并没有卡住。使用多进程库时,我最喜欢的一种调试方法是让子进程把信息写入文本文件,而不是直接打印到屏幕上。这样可以避免很多麻烦,比如不确定子进程是否继承了相同的输入输出,管道是否满了等等。如果我们把你的任务改成下面这样:
def task():
with open('taskfile.txt', 'w') as fo:
fo.write("Task started...")
# TODO: Start a native process here using Subprocess.popen
time.sleep(3)
fo.write("Task ended")
它会生成一个名为'taskfile.txt'的文本文件,里面包含以下内容:
任务开始...任务结束
所以你的任务运行和结束得很好。主程序只是等待输入。 我猜你没有看到“任务开始...”的提示,是因为用multiprocessing.Process()
启动的进程有自己的输入输出管道,这些管道并没有连接到主程序的控制台上。