15

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

そしてそれは「トップ」のように更新出力を続けるツールで起こります

私の最高の試練:

import os
import time
import subprocess

process = subprocess.Popen('top')

time.sleep(2)

os.popen("killall top")

print process

それは最初のもの(それはケリングされています)よりもうまく機能しましたが、それは戻ります:

<subprocess.Popen object at 0x97a50cc>

2回目の裁判:

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

変数「プロセス」に保存します。私はみんなを考えています、私は今本当に立ち往生していますか?

4

5 に答える 5

26
#!/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()とうまく相互作用しないかもしれませんが。@Alex Martelliの回答subprocessに基づく:

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()ブロックします。

于 2010-12-11T20:52:40.830 に答える
3

「top」を使用する代わりに、「ps」を使用することをお勧めします。これにより、同じ情報が得られますが、永遠に1秒に1回ではなく、1回だけです。

また、psでいくつかのフラグを使用する必要があります。私は「psaux」を使用する傾向があります

于 2010-12-11T17:41:47.513 に答える
0

実際、出力バッファーをいっぱいにすると、いくつかの答えで終わります。したがって、1つの解決策は、バッファを大きなガベージ出力(bufsize = 1で約6000文字)で満たすことです。

たとえば、topの代わりに、sys.stdoutに書き込むPythonスクリプトがあるとします。

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

ランチャー側では、単純なprocess.readline()の代わりに:

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

2000はサブプロセスの実装に依存しているため、少し汚れていることは確かですが、正常に機能し、非常に単純です。bufsize = 1以外を設定すると、問題が悪化します。

于 2013-01-26T22:15:50.000 に答える
0

このアプローチではなく、私が行うことは、情報を取得しようとしているプログラムを調べて、その情報の最終的なソースを決定することです。API呼び出しまたはデバイスノードの場合があります。次に、同じソースから取得するPythonを作成します。これにより、「スクレイピング」「調理済み」データの問題とオーバーヘッドが排除されます。

于 2010-12-11T20:52:24.697 に答える
0

(JFセバスティアンあなたのコードはうまく機能します、私はそれが私の解決策よりも優れていると思います=))

私は別の方法でそれを解決しました。

ターミナルで直接出力する代わりに、ファイル「tmp_file」にします。

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

助けてくれてありがとう

于 2010-12-12T14:50:22.793 に答える