2013-03-15 10 views
7

Possiedo un'applicazione Python intensiva della memoria (tra centinaia di MB e diversi GB).
Ho un paio di eseguibili Linux MOLTO PICCOLI che l'applicazione principale deve eseguire, ad es.Comprensione degli errori di allocazione di memoria e fork di Python

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

Quando si esegue queste utilità esterne (una volta, alla fine del lungo periodo processo principale) utilizzando subprocess.Popen talvolta vengono OSError: [Errno 12] Cannot allocate memory.
Non capisco perché ... Il processo richiesto è minuscolo!
Il sistema ha memoria sufficiente per molte altre shell.

Sto usando Linux (Ubuntu 12.10, 64 bit), quindi suppongo chiamate di subprocesso Fork.
E Fork forchetta il mio processo esistente, raddoppiando così la quantità di memoria consumata, e non riesce ??
Cosa è successo a "copia su scrittura"?

È possibile generare un nuovo processo senza fork (o almeno senza copiare memoria - avvio nuovo)?

correlati:

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

[Hai letto questa risposta alla domanda correlata] (http://stackoverflow.com/a/13329386/4279)? – jfs

+0

Ho, grazie. Ci sono alcune soluzioni alternative valide, alcune delle quali posso usarle. Speravo in una soluzione reale: la possibilità di generare un nuovo processo all'interno di Python che non copi tutta la memoria del processo alla fine. –

risposta

3

non sembra che una vera soluzione sarà imminente (cioè un'implementazione alternativa di sottoprocesso che usa vfork). Che ne dici di un bel trucco? All'inizio del processo, genera uno schiavo che si blocca con un piccolo ingombro di memoria, pronto a generare i tuoi sottoprocessi e mantenere una comunicazione aperta per tutta la durata del processo principale.

Ecco un esempio utilizzando Rfoo (http://code.google.com/p/rfoo/) con un socket UNIX di nome chiamato rfoosocket (si può ovviamente utilizzare altri tipi di connessione Rfoo supporti, o di un'altra libreria RPC):

Server:

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

Se avete bisogno di tempo reale avanti e indietro l'interazione con i tuoi coprocesso sottoprocessi deposto le uova questo modello probabilmente non funzionerà, ma potresti essere in grado di hackerarlo. Probabilmente vorrai ripulire gli argomenti disponibili che possono essere passati a Popen in base alle tue esigenze specifiche, ma tutto dovrebbe essere relativamente semplice.

Si dovrebbe anche trovare semplice avviare il server all'inizio del client e gestire il file socket (o la porta) da ripulire all'uscita.

+0

'Ropen' provoca un deadlock se' cmd' produce abbastanza output per riempire il suo buffer di pipe del sistema operativo stdout. – jfs

Problemi correlati