我有一个 Python 多处理应用程序,它使用多处理 API 启动“workers”。主进程本身由一个不是用 Python 编写的服务进程启动。工作人员可以自己使用 subprocess.Popen
启动其他非 Python 子进程。
为清楚起见,这是整个流程层次结构:
- service.exe:服务进程(原生 EXE)
- python.exe:Python 主进程(下面的程序)
- python.exe:Python子进程(进程启动的任务函数)
- subprocess.exe: native 子进程(见下面的解释)
- python.exe:Python子进程(进程启动的任务函数)
- 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 进程,我将不胜感激,但正是这种奇怪的阻塞行为让我做噩梦)
最佳答案
您的子流程没有挂起。当我使用多处理库时,我最喜欢使用的调试技术之一是让子进程删除文本文件而不是打印到标准输出,这样你就可以避免所有管道的复杂性,比如想知道你的子进程是否继承相同的标准输入/标准输出、完整管道等。如果我们将您的任务修改为以下内容:
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”:
Task started...Task ended
因此,您的任务正在正常运行和退出。 Main 只是在等待来自标准输入的输入。我怀疑您没有看到“任务已启动...”注释,因为使用 multiprocessing.Process()
启动的进程有自己的 stdin 和 stdout 管道,它们未连接到与 main 相同的控制台.
关于在主进程中从标准输入进行阻塞读取时,Python 子进程阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25681400/