Frage

Ich habe ein Python-Programm für Linux sieht fast aus wie diese:

import os
import time

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

time.sleep(1)

os.popen("killall top")

print process

das Programm hängt in dieser Zeile:

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

und das geschieht in den Werkzeugen, die Update-Ausgabe halten wie "Top"

meine besten Studien:

import os
import time
import subprocess

process = subprocess.Popen('top')

time.sleep(2)

os.popen("killall top")

print process

es funktionierte besser als die erste (es ist kelled), aber es gibt:

<subprocess.Popen object at 0x97a50cc>

der zweite Versuch:

import os
import time
import subprocess

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

time.sleep(2)

os.popen("killall top")

print process

die gleiche wie die erste. Es gehängt wegen "readlines ()"

Die Rückkehr sollte wie folgt sein:

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

und speichern in der Variablen „Prozess“. Irgendwelche I Idee Jungs, ich bin jetzt wirklich fest?

War es hilfreich?

Lösung

#!/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()

schweifartigen Lösungen, die nur den Teil der Ausgabe

drucken

Sie könnten den Prozessausgang in einem anderen Thread lesen und die erforderliche Anzahl von den letzten Zeilen in einer Warteschlange speichern:

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

Diese Variante erfordert q.append() atomare Operation zu sein. Andernfalls könnte der Ausgang beschädigt werden.

signal.alarm() Lösung

könnten Sie verwenden signal.alarm() die process.terminate() nach bestimmten Timeout zu rufen, anstatt die in einem anderen Thread zu lesen. Obwohl es in Wechselwirkung tritt vielleicht nicht sehr gut mit dem subprocess Modul. Basierend auf @ Alex Martelli Antwort :

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

Dieser Ansatz funktioniert nur auf * nix-Systemen. Es könnte sperren, wenn process.stdout.readline() nicht zurück.

threading.Timer Lösung

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

Dieser Ansatz sollte auch unter Windows arbeiten. Hier habe ich gebraucht process.stdout als iterable haben; es könnte eine zusätzliche Ausgabepufferung einführen, können Sie zum iter(process.stdout.readline, "") Ansatz wechseln könnte, wenn es nicht erwünscht ist. wenn der Prozess nicht beendet, auf process.terminate() dann der Skripts hängt.

Keine Fäden, keine Signale Lösung

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

Diese Variante Gebrauch weder Fäden, keine Signale, aber es erzeugt eine Ausgabe im Terminal verstümmelt. Es wird blockiert, wenn process.stdout.readline() Blöcke.

Andere Tipps

Anstelle von „oben“ Ich schlage vor, mit „ps“ verwendet, die geben Ihnen die gleichen Informationen, aber nur einmal statt einmal pro Sekunde für alle Ewigkeit.

Sie müssen auch einige Fahnen mit ps verwenden, neige ich dazu, „ps aux“

zu verwenden,

Was ich tun würde, anstatt dieser Ansatz ist das Programm prüfen Sie versuchen, Informationen aus und bestimmen die ultimative Quelle dieser Informationen zu erhalten. Es kann ein API-Aufruf oder Geräteknoten sein. Dann schreiben Sie einige Python, die es aus der gleichen Quelle erhält. Das eliminiert „die Probleme und Overhead„Schaben““ Daten gekocht.

(J. F. Sebastian Ihre Codes lassen sich gut, ich denke, es ist besser als meine Lösung =))

Ich habe es gelöst andere Art und Weise verwendet wird.

Statt den Ausgang direkt am Terminal macht ich es in eine Datei „tmp_file“ machen:

top >> tmp_file

Dann habe ich das Tool „cut“ seinen Ausgang zu machen „die Top-Ausgang ist“ als Prozesswert

cat tmp_file

und es tat, was ich will es tun .Diese der endgültige Code lautet:

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

Vielen Dank Jungs für Hilfe

Fakten, wenn Sie den Ausgabepuffer zu füllen, werden Sie mit etwas Antwort beenden. So eine Lösung ist, die Puffer mit einem großen Müll Ausgang (~ 6000 Zeichen mit bufsize = 1).

füllen

Lassen Sie uns sagen, statt oben, haben Sie ein Python-Skript, das schreiben auf sys.stdout:

GARBAGE='.\n'
sys.stdout.write(valuable_output)
sys.stdout.write(GARBAGE*3000)

Auf der Abschuss Seite, statt einfach process.readline ():

GARBAGE='.\n'
line=process.readline()
while line==GARBAGE:
   line=process.readline()

Ganz sicher ist es ein bisschen schmutzig, wie 2000 über subprocess Umsetzung abhängig ist, aber es funktioniert gut und ist sehr einfach. Einstellung alles andere als BUFSIZE = 1 die Sache noch schlimmer zu machen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top