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

我有一个用于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

它比第一个更好(它已经发了声),但是返回了:

<subprocess.Popen object at 0x97a50cc>

第二次审判:

import os

import time

import subprocess

process = subprocess.Popen('top').readlines()

time.sleep(2)

os.popen("killall top")

print process

与第一个相同。由于“ 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”中。我知道吗,我现在真的很困吗?

回答:

#!/usr/bin/env python

"""Start process; wait 2 seconds; kill the process; print all process output."""

import subprocess

import tempfile

import time

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

signal.alarm()

你可以用来 在指定的超时后signal.alarm()调用,process.terminate()而不用读入另一个线程。尽管它可能无法与subprocess模块很好地交互。基于@Alex Martelli的答案:

import collections

import signal

import subprocess

class Alarm(Exception):

pass

def alarm_handler(signum, frame):

raise Alarm

def 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 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()

这种方法在Windows上也应适用。在这里,我用作process.stdout迭代。它可能会引入额外的输出缓冲,iter(process.stdout.readline, “”)如果不希望的话,你可以切换到该方法。如果进程没有终止,process.terminate()则脚本挂起。

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

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()

此变型既不使用线程,也不使用信号,但会在终端中产生乱码输出。如果process.stdout.readline()阻塞,它将阻塞。

以上是 停止读取Python中没有挂起的进程输出? 的全部内容, 来源链接: utcz.com/qa/414414.html

回到顶部