2015-06-15 4 views
5

In meinem aktuellen Projekt habe ich einen Webserver, der Linux-Befehle aufruft, um Informationen zu erhalten, die dann auf der Website angezeigt werden. Das Problem damit ist, dass der Webserver auf einem winzigen Embedded-Gerät läuft (es ist im Grunde ein Konfigurations-Tool für das Gerät), das nur 256 MB RAM hat. Der Webserver selbst benötigt mehr als die Hälfte des freien Arbeitsspeichers, den ich auf diesem Gerät habe.subprocess.check_output ohne hohe Speicherauslastung

Jetzt, wenn ich versuche, subprocess.check_output() zu verwenden, um einen Befehl aufzurufen, verdoppelt die Gabel kurz die RAM-Nutzung (weil es den Elternprozess oder so etwas klont, soweit ich verstehe) und stürzt somit das Ganze mit einem ab "Out of Memory", obwohl der genannte Prozess ziemlich klein ist.

Da das Gerät ziemlich billige Flash-Chips verwendet, die sich als überlastet erwiesen haben, möchte ich keine Swap-Lösungen oder andere Lösungen verwenden, die auf der Erhöhung des virtuellen Speichers basieren.

Was ich bis jetzt versucht habe, ist, eine Sh-Sitzung zu Beginn des Programms zu poppen, wenn es immer noch wenig Speicher belegt, und dann die Befehle in diese sh-Sitzung zu schreiben und die Ausgabe zu lesen. Das funktioniert irgendwie, aber es ist ziemlich instabil, da ein falscher "Ausgang" oder etwas Ähnliches das Ganze zum Absturz bringen kann.

Gibt es eine Lösung ähnlich wie subprocess.check_output(), die meine Speicherbelegung nicht verdoppelt?

+0

Welchen Webserver benutzen Sie BTW? –

+0

Es ist ein selbstprogrammiertes Programm, das web.py als Framework verwendet. – Dakkaron

+0

Möchten Sie es irgendwo posten, damit wir einen Blick riskieren können? –

Antwort

5

Also mit Hilfe von J. F. Sebastian habe ich es herausgefunden.

Dies ist der Code, den ich am Ende verwendet:

from multiprocessing import Process, Queue 
from subprocess import check_output, CalledProcessError 

def cmdloop(inQueue,outQueue): 
    while True: 
     command = inQueue.get() 
     try: 
      result = check_output(command,shell=True) 
     except CalledProcessError as e: 
      result = e 

     outQueue.put(result) 

inQueue = Queue() 
outQueue = Queue() 
cmdHostProcess = Process(target=cmdloop, args=(inQueue,outQueue,)) 
cmdHostProcess.start() 

def callCommand(command): 
    inQueue.put(command) 
    return outQueue.get() 

def killCmdHostProcess(): 
    cmdHostProcess.terminate() 

In Python 3.4+ habe ich multiprocessing.set_start_method ('forkserver') haben könnte, aber da dies auf Python läuft 2.7 ist dies leider nicht verfügbar .

Noch dies reduziert meinen Speicherverbrauch auf lange Sicht und beseitigt das Problem auf eine saubere Art und Weise. Vielen Dank für die Hilfe!

+1

Dies ist eine nette Lösung für das Problem, aber die Tatsache, dass Python dies in erster Linie notwendig macht, ist schrecklich. –

+0

Schöne Lösung! Es lohnt sich, darauf hinzuweisen, dass Sie "shell = True" nicht leicht verwenden sollten, wie auch in der Dokumentation unter https://docs.python.org/2/library/subprocess.html#frequently-used-arguments erwähnt hat auch einen negativen Einfluss auf die RAM-Nutzung (zwei Gabeln statt einer vielleicht?). Vielleicht möchten Sie auch OSError's fangen. – phk

+0

Haben Sie einen Beweis dafür, dass diese zusätzliche Kopie einen erheblichen Aufwand verursacht? AFAIK der Copy-on-Write sollte diesen Overhead vermeiden. – Mohit