2014-09-05 110 views
2

我有一个Python多处理应用程序,它启动使用多处理API的“工作人员”。主进程本身是由一个不用Python编写的服务进程启动的。工作人员可能会使用subprocess.Popen开始其他非Python子流程。Python子进程阻止在主进程中阻止从标准输入读取

为了清楚起见,这是整个过程的层次结构:

  • service.exe:服务过程(天然EXE)
    • python.exe:Python的主处理(以下程序)
      • 蟒.exe:Python子进程(任务函数由进程启动)
        • subprocess.exe:本机子进程(请参阅下面的说明)

当服务过程停止,它必须告诉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进程,我会很感激,但这是奇怪的阻止行为,给我做恶梦)

回答

0

你的子进程aren不挂。当我使用多处理库时,我最喜欢使用的调试技术之一是让子流程放弃文本文件而不是打印到标准输出,这样可以避免管道的所有复杂问题,比如想知道子流程是否继承同样的标准输入/输出,全管道等如果我们修改你的任务是以下几点:

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”:

任务开始...任务结束

因此,您的任务正在运行并正常退出。Main只是在等待来自stdin的输入。我怀疑你没有看到“Task started ...”笔记,因为使用multiprocessing.Process()启动的进程有自己的标准输入和标准输出管道,它们没有连接到与main相同的控制台。

+0

在我的真实应用程序中(上面的代码只是一个简单的测试程序,我希望能够重现该问题),子进程写入数据库以将“作业”标记为“进行中”。当且仅当主进程阻止从标准输入读取时,才会发生这种情况。 但是,我同意上述示例可能不会重现实际问题,或者出于其他原因可能无法打印“任务已结束”。 我也忘了提及一位同事无法在他的机器上重现问题。如果我找到时间,我会尝试使用示例程序的调试技巧... – 2014-09-10 20:03:32

+0

您在您的问题中提出的假设是正确的:从主标准输入读取的阻止读取应该对您的子流程执行没有影响。尝试添加几个文本文件写入到您的子过程中,您将添加用于调试的打印语句的相同方式,并尝试缩小子流程的挂起位置。如果您无法用他们提供的信息解决问题,请尝试在问题中添加一些真实的代码。看看你是如何启动子过程以及任务函数中的所有内容(包括挂起的语句)将会很有帮助。 – skrrgwasme 2014-09-10 20:08:05

+0

@FlorianWinter你在使用什么样的数据库?本机支持的数据库之一?在没有看到任何与数据库相关的代码的情况下,我会建议检查以确保您的主进程在等待stdin时不保存任何数据库资源,并确保您的子进程修改数据库的方式是线程安全的。如果两个子进程之间发生冲突,这两个进程都试图同时修改数据库,则可能是数据丢失或死锁。 – skrrgwasme 2014-09-13 17:44:56