【问题标题】:Problems with python subprocess and stdoutpython子进程和stdout的问题
【发布时间】:2018-09-20 05:30:00
【问题描述】:

尝试使用subprocess.Popen 在单独的线程中创建一个运行一些 bash 作业(用于闪烁)的 python 脚本。在运行时,我想读取进程的标准输出,以便我可以在一个简单的 curses 界面中向用户显示一些进度。所以每个线程运行如下:

def worker(panel):
    panel['status'] = 'STARTING'
    panel['process'] = Popen([SCRIPTFILE, panel['ip'], FWFILE, JADFILE, EXEFILE], stdout=PIPE, bufsize=1048576)
    panel['status'] = 'RUNNING'

    line = " "
    while line:
        line = panel['process'].stdout.readline()
        panel['status'] = line
    panel['status'] = 'DONE'

在这种情况下,我在 UI 中看到状态卡在 STARTING 上,但查看 IP 流量,它似乎确实在运行,但从未返回任何输出。所以看起来Popen 实际运行了这项工作但没有返回。一旦其他进程完成,它似乎就会停止挂起,我会在缓冲时立即获取所有数据。我已经看到有关在子进程上从标准输出读取的警告,但这些警告似乎与其他场景有关。而且我不能真正使用communicate(),因为它正在等待进程完成。知道是什么让Popen 像这样挂起来吗?

尝试制作一个显示问题的最小版本(在 Linux 上使用 python 2.7 运行(如果是 windows,则更改脚本中的查找路径)):

import curses
import time
from subprocess import *
import threading

def check_done(panels):
    done = True

    for panel in panels:
        if panel['status'] != 'DONE':
            done = False
            break

    return done

def flash_worker(panel):
    panel['status'] = 'STARTING'

    panel['process'] = Popen(["find", "/usr"], stdout=PIPE, bufsize=1048576)

    panel['status'] = 'RUNNING'

    line = " "

    while line:
        line = panel['process'].stdout.readline()

        panel['status'] = line

    panel['status'] = 'DONE'

def ui_worker(panels):
    stdscr = curses.initscr()
    curses.noecho()
    curses.cbreak()
    stdscr.keypad(1)
    stdscr.scrollok(1)

    stdscr.erase()
    stdscr.refresh()

    while not check_done(panels):
        y = 0

        stdscr.clear()

        stdscr.addstr(y, 0, "IP")
        stdscr.addstr(y, 15, "Status")

        height, width = stdscr.getmaxyx()

        for i in range(0, len(panels)):
            y = y + 1
            stdscr.addstr(y, 0, "%s" % (panels[i]['ip']))
            stdscr.addstr(y, 15, "%s" % (panels[i]['status']))

        stdscr.refresh()
        time.sleep(0.1)

    curses.nocbreak();
    stdscr.keypad(0);
    curses.echo()
    curses.endwin()

def main():
    panels = []

    for i in range(0,25):
        panels.append({ 'ip' : '192.168.0.%d' % (i), 'mac' : '', 'status' : '', 'thread' : None, 'success' : False })

    for panel in panels:
        panel['thread'] = threading.Thread(name='Panel %s' % (panel['ip']), target = flash_worker, args = (panel,))
        panel['thread'].start()

    try:
        ui_worker(panels)
    except KeyboardInterrupt:
        print "Caught KeyboardInterrupt, terminating..."

    for panel in panels:
        panel['thread'].join()

if __name__ == "__main__":
    main()

【问题讨论】:

标签: python subprocess popen freeze


【解决方案1】:

找到了解决方案,但不是 100% 确定它为什么有效。但是在分叉(使用 Popen)时设置 close_fds=True 可以解决问题。

【讨论】:

    猜你喜欢
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2021-06-02
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多