为了账号安全,请及时绑定邮箱和手机立即绑定

停止读取Python中的进程输出而不挂起?

停止读取Python中的进程输出而不挂起?

临摹微笑 2019-07-11 10:32:43
停止读取Python中的进程输出而不挂起?我有一个用于Linux的Python程序,与此类似:import osimport time process = os.popen("top").readlines()time.sleep(1)os.popen("killall top")print process程序挂在下面一行:process = os.popen("top").readlines()这种情况发生在那些不断更新输出的工具中,比如“top”我最好的审判:import osimport timeimport subprocess process = subprocess.Popen('top')time.sleep(2)os.popen("killall top")print process它比第一个更好地工作(它已经被封住了),但是它返回:<subprocess.Popen object at 0x97a50cc>第二次审判:import osimport timeimport subprocess process = subprocess.Popen('top').readlines()time.sleep(2)os.popen("killall top")print process和第一个一样。由于“readline()”,它挂了。它的返回应该是这样的:   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND             31735 Barakat   20   0  246m  52m  20m S 19.4  2.7  13:54.91 totem                1907 root      20   0 91264  45m  15m S  1.9  2.3  38:54.14 Xorg                 2138 Barakat   20   0 17356 5368 4284 S  1.9  0.3   3:00.15 at-spi-registry      2164 Barakat    9 -11  164m 7372 6252 S  1.9  0.4   2:54.58 pulseaudio           2394 Barakat   20   0 27212 9792 8256 S  1.9  0.5   6:01.48 multiload-apple      6498 Barakat   20   0 56364  30m  18m S  1.9  1.6   0:03.38 pyshell                 1 root      20   0  2880 1416 1208 S  0.0  0.1   0:02.02 init                    2 root      20   0     0    0    0 S  0.0  0.0   0:00.02 kthreadd                3 root      RT   0     0    0    0 S  0.0  0.0   0:00.12 migration/0             4 root      20   0     0    0    0 S  0.0  0.0   0:02.07 ksoftirqd/0             5 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 watchdog/0并保存在变量“Process”中。我有什么想法吗,伙计们,我现在真的被困住了?
查看完整描述

3 回答

?
MMMHUHU

TA贡献1834条经验 获得超8个赞

#!/usr/bin/env python"""Start process; wait 2 seconds; kill the process; print all process output.""
"import subprocessimport tempfileimport timedef main():
    # open temporary file (it automatically deleted when it is closed)
    #  `Popen` requires `f.fileno()` so `SpooledTemporaryFile` adds nothing here
    f = tempfile.TemporaryFile() 

    # start process, redirect stdout
    p = subprocess.Popen(["top"], stdout=f)

    # wait 2 seconds
    time.sleep(2)

    # kill process
    #NOTE: if it doesn't kill the process then `p.wait()` blocks forever
    p.terminate() 
    p.wait() # wait for the process to terminate otherwise the output is garbled

    # print saved output
    f.seek(0) # rewind to the beginning of the file
    print f.read(), 
    f.close()if __name__=="__main__":
    main()

只打印输出部分的类似尾部的解决方案

您可以在另一个线程中读取进程输出,并在队列中保存所需的最后一行数:

import collectionsimport subprocessimport timeimport threadingdef read_output(process, append):
    for line in iter(process.stdout.readline, ""):
        append(line)def main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)
    try:
        # save last `number_of_lines` lines of the process output
        number_of_lines = 200
        q = collections.deque(maxlen=number_of_lines) # atomic .append()
        t = threading.Thread(target=read_output, args=(process, q.append))
        t.daemon = True
        t.start()

        #
        time.sleep(2)
    finally:
        process.terminate() #NOTE: it doesn't ensure the process termination

    # print saved lines
    print ''.join(q)if __name__=="__main__":
    main()

这个变体需要q.append()成为原子操作。否则,输出可能损坏。

signal.alarm()

你可以用signal.alarm()调用process.terminate()在指定超时后,而不是在另一个线程中读取。虽然它可能与subprocess模块。基于@Alex Martelli的回答:

import collectionsimport signalimport subprocessclass Alarm(Exception):
    passdef alarm_handler(signum, frame):
    raise Alarmdef main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

    # set signal handler
    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(2) # produce SIGALRM in 2 seconds

    try:
        # save last `number_of_lines` lines of the process output
        number_of_lines = 200
        q = collections.deque(maxlen=number_of_lines)
        for line in iter(process.stdout.readline, ""):
            q.append(line)
        signal.alarm(0) # cancel alarm
    except Alarm:
        process.terminate()
    finally:
        # print saved lines
        print ''.join(q)if __name__=="__main__":
    main()

这种方法只适用于*nix系统。如果process.stdout.readline()不会再回来了。

threading.Timer

import collectionsimport subprocessimport threadingdef main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

    # terminate process in timeout seconds
    timeout = 2 # seconds
    timer = threading.Timer(timeout, process.terminate)
    timer.start()

    # save last `number_of_lines` lines of the process output
    number_of_lines = 200
    q = collections.deque(process.stdout, maxlen=number_of_lines)
    timer.cancel()

    # print saved lines
    print ''.join(q),if __name__=="__main__":
    main()

这种方法也应该适用于Windows。我用过process.stdout作为一个可迭代的;它可能会引入一个额外的输出缓冲,您可以切换到iter(process.stdout.readline, "")如果这是不可取的,就接近它。如果进程未在process.terminate()然后脚本挂起。

没有线程,没有信号解决方案

import collectionsimport subprocessimport sysimport timedef main():
    args = sys.argv[1:]
    if not args:
        args = ['top']

    # start process, redirect stdout
    process = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)

    # save last `number_of_lines` lines of the process output
    number_of_lines = 200
    q = collections.deque(maxlen=number_of_lines)

    timeout = 2 # seconds
    now = start = time.time()    
    while (now - start) < timeout:
        line = process.stdout.readline()
        if not line:
            break
        q.append(line)
        now = time.time()
    else: # on timeout
        process.terminate()

    # print saved lines
    print ''.join(q),if __name__=="__main__":
    main()

这个变体既不使用线程,也不使用信号,但它在终端中产生错误的输出。如果process.stdout.readline()街区。


查看完整回答
反对 回复 2019-07-11
?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

我建议使用“ps”代替“top”,这将给您提供相同的信息,但只有一次,而不是一秒,在所有的永恒。

您还需要在ps中使用一些标志,我倾向于使用“ps aux”


查看完整回答
反对 回复 2019-07-11
?
MMTTMM

TA贡献1869条经验 获得超4个赞

我用另一种方法解决了。

与直接在终端上输出不同,我将其转换为一个文件“tmp_file”:

top >> tmp_file

然后,我使用工具“剪切”使它的输出“是最高输出”作为过程的值。

cat tmp_file

它做了我想做的这是最后的代码:

import osimport subprocessimport time

subprocess.Popen("top >> tmp_file",shell = True)time.sleep(1)os.popen("killall top")
process = os.popen("cat tmp_file").read()os.popen("rm tmp_file")print process# Thing better than nothing =)

非常感谢你们的帮助


查看完整回答
反对 回复 2019-07-11
  • 3 回答
  • 0 关注
  • 456 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信