Python 子进程问题

4 投票
4 回答
1250 浏览
提问于 2025-04-15 12:49

我想在Python中启动一个进程,并实现双向通信。当然,Pexpect可以做到这一点,确实是我可能会考虑的一种方法。不过,这并不是最理想的选择。

我理想的情况是有一种跨平台的通用方法,只用标准的Python库。Subprocess这个模块已经很接近了,但我必须等进程结束后才能安全地与它互动,这让我觉得不太方便。

查看文档后,我发现可以直接操作stdin、stdout和stderr这些文件描述符,但有个大大的警告说“不要这样做”。不幸的是,这个警告的原因并不是很清楚,但从我在网上查到的信息来看,这和操作系统的缓冲有关。如果这些内部缓冲出现问题,可能会导致代码意外地死锁(顺便说一下,如果有示例能展示错误的做法和正确的做法,我会很感激)。

所以,冒着代码可能死锁的风险,我想尝试使用poll或select来与正在运行的进程进行交互式读取,而不杀掉它。虽然这样可能失去跨平台的能力,但我喜欢它不需要额外的库。更重要的是,我想知道这样做是否是个好主意。我还没有尝试这种方法,但我担心可能会有一些问题会严重影响我的程序。这样做能行吗?我应该测试哪些内容?

在我的具体情况下,我并不太关心能否向进程写入数据,只是想不断地从中读取数据。而且,我不期望我的进程会输出大量文本,所以我希望能避免死锁的问题,不过我想知道这些限制到底是什么,并能够写一些测试来看看在哪些情况下会出问题。

4 个回答

1

我在一个单独的线程中做这个,使用消息队列来让不同的线程之间进行沟通。在我的情况下,子进程会把完成的百分比打印到标准输出(也就是屏幕上)。我想让主线程显示一个漂亮的进度条。

 if sys.platform == 'win32':
        self.shell = False
        self.startupinfo = subprocess.STARTUPINFO()
        self.startupinfo.dwFlags = 0x01
        self.startupinfo.wShowWindow = 0
    else:
        self.shell = True
        self.startupinfo = None

. . .

f = subprocess.Popen( cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env = env, shell = self.shell, startupinfo = self.startupinfo )
    f.stdin.close()
    line = ''
    while True:
        log.debug('reading')
        c = f.stdout.read(1)

        log.debug(c)

        if len(c) == 0:
            log.info('stdout empty; must be done')
            break;
        if ord(c) == 13:
            continue
        if c == '%':
            # post % complete message to waiting thread.
            line = ''
        else:
            line += c


    log.info('checking for errors')
    errs = f.stderr.readlines()

    if errs:
        prettyErrs = 'Reported Errors: '
        for i in errs:
            prettyErrs += i.rstrip('\n')

        log.warn( prettyErrs )
        #post errors to waiting thread
    else:
        print 'done'        
    return
3

在Python 2.6的标准库中,使用模块。

这个模块里面有一个,可以用来进行读和写操作。

0

请原谅我对这个话题的无知,但你难道不可以用 -u 这个参数来启动 Python 吗?这个参数的意思是“无缓冲”。

这可能也会引起你的兴趣……http://www.gossamer-threads.com/lists/python/python/658167

撰写回答