停止读取Python中没有挂起的进程输出?

停止读取Python中没有挂起的进程输出?,python,subprocess,multiprocessor,hung,Python,Subprocess,Multiprocessor,Hung,我有一个针对Linux的Python程序,看起来几乎像这样: import os import time process = os.popen("top").readlines() time.sleep(1) os.popen("killall top") print process 程序挂起在这一行: process = os.popen("top").readlines() 这种情况发生在那些像“Top”一样保持更新输出的工具中 我的最佳尝试: import os import

我有一个针对Linux的Python程序,看起来几乎像这样:

import os
import time

process = os.popen("top").readlines()

time.sleep(1)

os.popen("killall top")

print process
程序挂起在这一行:

process = os.popen("top").readlines()
这种情况发生在那些像“Top”一样保持更新输出的工具中

我的最佳尝试:

import os
import time
import subprocess

process = subprocess.Popen('top')

time.sleep(2)

os.popen("killall top")

print process
它比第一个(kelled)更有效,但它的回报是:

<subprocess.Popen object at 0x97a50cc>
和第一个一样。由于“readlines()”而挂起

它的返回应该是这样的:

top - 05:31:15 up 12:12,  5 users,  load average: 0.25, 0.14, 0.11
Tasks: 174 total,   2 running, 172 sleeping,   0 stopped,   0 zombie
Cpu(s):  9.3%us,  3.8%sy,  0.1%ni, 85.9%id,  0.9%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1992828k total,  1849456k used,   143372k free,   233048k buffers
Swap:  4602876k total,        0k used,  4602876k free,  1122780k cached

  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         
    9 root      20   0     0    0    0 S  0.0  0.0   0:01.43 events/0           
   11 root      20   0     0    0    0 S  0.0  0.0   0:00.00 cpuset             
   12 root      20   0     0    0    0 S  0.0  0.0   0:00.02 khelper            
   13 root      20   0     0    0    0 S  0.0  0.0   0:00.00 netns              
   14 root      20   0     0    0    0 S  0.0  0.0   0:00.00 async/mgr          
   15 root      20   0     0    0    0 S  0.0  0.0   0:00.00 pm
并保存在变量“process”中。伙计们,我现在真的被卡住了吗?

我建议用“ps”代替“top”,它会给你同样的信息,但只能一次,而不是永远一秒钟一次


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

而不是这种方法,我要做的是检查您试图从中获取信息的程序,并确定该信息的最终来源。它可能是API调用或设备节点。然后,编写一些python,从同一个源代码获取它。这消除了“抓取”已处理数据的问题和开销

仅打印输出部分的尾部解决方案 您可以在另一个线程中读取进程输出,并保存队列中最后一行的所需数量:

import collections
import subprocess
import time
import threading

def 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()
是原子操作。否则,输出可能已损坏

解决方案 您可以使用在指定的超时后调用
进程。terminate()
,而不是在另一个线程中读取。尽管它可能与
子流程
模块的交互不太好。基于:

此方法仅适用于*nix系统。如果
process.stdout.readline()
没有返回,它可能会阻塞

解决方案 这种方法也适用于Windows。这里我使用了
process.stdout
作为一个iterable;它可能会引入额外的输出缓冲,如果不需要,您可以切换到
iter(process.stdout.readline,”)
方法。如果进程没有在
process.terminate()
上终止,则脚本将挂起

没有线程,就没有信号解决方案
导入集合
导入子流程
导入系统
导入时间
def main():
args=sys.argv[1:]
如果不是args:
args=['top']
#启动进程,重定向标准输出
process=subprocess.Popen(args,stdout=subprocess.PIPE,close_fds=True)
#保存流程输出的最后“行数”
_线的数量=200
q=collections.deque(maxlen=行数)
超时=2秒
现在=开始=时间。时间()
while(现在-启动)<超时:
line=process.stdout.readline()
如果不是直线:
打破
q、 追加(行)
now=time.time()
否则:#超时
process.terminate()
#打印保存的行
打印“”连接(q),
如果名称=“\uuuuu main\uuuuuuuu”:
main()
这种变体既不使用线程,也不使用信号,但会在终端中产生乱码输出。如果
process.stdout.readline()
阻塞,它将被阻塞。

(J.F.Sebastian您的代码工作得很好,我认为它比我的解决方案好=)

我用另一种方法解决了它

我没有直接在终端上生成输出,而是将其生成一个文件“tmp_file”:

然后我使用工具“cut”将其输出“这是最高输出”作为流程的值

cat tmp_file
它做了我想要它做的。这是最后的代码:

import os
import subprocess
import 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 =)

非常感谢大家在事实方面提供的帮助,如果你填满了输出缓冲区,你会得到一些答案。因此,一种解决方案是用一个大的垃圾输出(大约6000个字符,bufsize=1)填充缓冲区

比方说,您有一个在sys.stdout上编写的python脚本,而不是top:

GARBAGE='.\n'
sys.stdout.write(valuable_output)
sys.stdout.write(GARBAGE*3000)
在启动器端,而不是简单的进程。readline()


它确实有点脏,因为2000依赖于子流程的实现,但它工作得很好,而且非常简单。设置bufsize=1以外的任何值都会使事情变得更糟。

子流程。Popen
对象没有属性
读取行
。top就是这种程序的完美示例。。。你没用陀螺吗?你在用什么程序?airodump ng这是Aircrack ng tools中的一个工具,它的输出像Top。非常感谢,这太棒了。上面的代码有许多问题,例如,
os.popen()
不应像代码2中那样使用。我已经更新了我的答案,包括一个打印所有程序输出的变体(不仅仅是从末尾开始的指定行数)
import collections
import subprocess
import threading

def 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()
import collections
import subprocess
import sys
import time

def 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()
top >> tmp_file
cat tmp_file
import os
import subprocess
import 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 =)
GARBAGE='.\n'
sys.stdout.write(valuable_output)
sys.stdout.write(GARBAGE*3000)
GARBAGE='.\n'
line=process.readline()
while line==GARBAGE:
   line=process.readline()