2013-03-15 9 views
7

Mam aplikację Python intensywnie wykorzystującą pamięć (od setek MB do kilku GB).
Posiadam kilka BARDZO MAŁYM plików wykonywalnych systemu Linux, do uruchomienia głównej aplikacji, np.Opis błędów przydziału widżetów i pamięci w języku Python

child = Popen("make html", cwd = r'../../docs', stdout = PIPE, shell = True) 
child.wait() 

Kiedy uruchamiam tych narzędzi zewnętrznych (raz, na końcu długiego biegu głównego procesu) używając subprocess.Popen ja czasami OSError: [Errno 12] Cannot allocate memory.
Nie rozumiem, dlaczego ... Żądany proces jest mały!
System ma wystarczającą ilość pamięci dla wielu innych powłok.

Używam Linuksa (Ubuntu 12.10, 64 bity), więc domyślam się, że podprocedie nazywają się Fork.
Widelec rozwidla mój istniejący proces, podwajając w ten sposób ilość zużywanej pamięci i nie działa?
Co stało się z "kopią przy pisaniu"?

Czy mogę utworzyć nowy proces bez widelca (lub przynajmniej bez kopiowania pamięci - rozpoczęcie od nowa)?

pokrewne:

The difference between fork(), vfork(), exec() and clone()

fork() & memory allocation behavior

Python subprocess.Popen erroring with OSError: [Errno 12] Cannot allocate memory after period of time

Python memory allocation error using subprocess.Popen

+1

[Czy znasz tę odpowiedź na powiązane pytanie] (http://stackoverflow.com/a/13329386/4279)? – jfs

+0

Mam, dzięki. Istnieje kilka cennych sposobów obejścia tego problemu, z których część mogę wykorzystać. Miałem nadzieję na prawdziwe rozwiązanie - możliwość odrodzenia się nowego procesu z poziomu Pythona, który nie kopiuje całej pamięci procesu a la fork. –

Odpowiedz

3

Nie wydaje się, że prawdziwym rozwiązaniem będzie przyszły (czyli alternatywną realizację podproces że używa vfork). A co powiesz na uroczy hack? Na początku procesu odradzamy niewolnika, który kręci się z niewielkim śladem pamięci, gotowym do odrodzenia twoich podprocesów i utrzymywania otwartej komunikacji przez cały czas trwania głównego procesu.

Oto przykład przy użyciu rfoo (http://code.google.com/p/rfoo/) o nazwie Gniazdo UNIX zwanego rfoosocket (można oczywiście wykorzystać inne rodzaje połączeń rfoo podpór, lub innej biblioteki RPC):

Serwer:

import rfoo 
import subprocess 

class MyHandler(rfoo.BaseHandler): 
    def RPopen(self, cmd): 
     c = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 
     c.wait() 
     return c.stdout.read() 

rfoo.UnixServer(MyHandler).start('rfoosocket') 

Client :

import rfoo 

# Waste a bunch of memory before spawning the child. Swap out the RPC below 
# for a straight popen to show it otherwise fails. Tweak to suit your 
# available system memory. 
mem = [x for x in range(100000000)] 

c = rfoo.UnixConnection().connect('rfoosocket') 

print rfoo.Proxy(c).RPopen('ls -l') 

Jeśli potrzebujesz interakcji koprocesów w czasie rzeczywistym tam i z powrotem ze spłodzonymi podprocesami, model ten prawdopodobnie nie będzie działać, ale możesz go włamać. Prawdopodobnie będziesz chciał wyczyścić dostępne argumenty, które można przekazać Popenowi w zależności od Twoich konkretnych potrzeb, ale to wszystko powinno być stosunkowo proste.

Powinieneś także znaleźć proste uruchomienie serwera na początku klienta i zarządzanie plikiem gniazda (lub portem), który ma zostać oczyszczony przy wyjściu.

+0

'Ropen' powoduje zakleszczenie, jeśli' cmd' generuje wystarczającą ilość danych wyjściowych, aby wypełnić standardowy bufor potoku OS. – jfs

Powiązane problemy