web-dev-qa-db-fra.com

Comment éviter [Errno 12] Impossible d'allouer les erreurs de mémoire causées par l'utilisation du module de sous-processus

Cas de test de travail complet

Bien sûr, en fonction de votre mémoire sur les machines locales et distantes, les tailles de votre baie seront différentes.

z1 = numpy.random.Rand(300000000,2);
for i in range(1000):
  print('*******************************************\n'); 
  direct_output = subprocess.check_output('ssh blah@blah "ls /"', Shell=True);
  direct_output = 'a'*1200000; 
  a2 = direct_output*10;
  print(len(direct_output));

Cas d'utilisation actuel

Dans le cas où cela aide mon cas d'utilisation est le suivant:

J'émets des requêtes db puis stocke les tables résultantes sur la machine distante. Je veux ensuite les transférer sur un réseau et faire une analyse. Jusqu'à présent, j'ai fait quelque chose comme ceci en python:

#run a bunch of queries before hand with the results in remote files

....
counter = 0
mergedDataFrame = None
while NotDone:
  output = subprocess.check_output('ssh blah@blah cat /data/file%08d'%(counter))
  data = pandas.read_csv(...)
  #do lots of analysis, append, merge, numpy stuff etc...
  mergedDataFrame = pandas.merge(...)
  counter += 1

À un moment donné, je reçois l'erreur suivante lors de la commande check_output: [Errno 12] Impossible d'allouer de la mémoire

Contexte

Grâce aux questions ci-dessous, je pense avoir une idée de ce qui ne va pas. Il existe un certain nombre de solutions publiées et j'essaie de déterminer laquelle des solutions évitera [Errno 12] Impossible d'allouer l'erreur de mémoire associée à la mise en œuvre du sous-processus à l'aide de fork/clone.

Python subprocess.Popen "OSError: [Errno 12] Cannot allocate memory" Ceci donne le diagnostic sous-jacent et suggère une solution de contournement comme le lancement d'un script séparé etc ...

Comprendre Python erreurs d'allocation de fork et de mémoire Suggère d'utiliser rfoo pour contourner la limitation de sous-processus de fork/clone et le processus enfant de frai et copier la mémoire etc ... Cela semble impliquer un modèle client-serveur

Quel est le moyen le plus simple de SSH en utilisant Python? , mais j'ai des contraintes supplémentaires que je ne peux pas utiliser de sous-processus en raison de limitations de mémoire et de l'implémentation de fork/clone? Les solutions suggèrent d'utiliser paramiko ou quelque chose de construit dessus, d'autres suggèrent un sous-processus (que j'ai trouvé ne fonctionnera pas dans mon cas).

Il y avait d'autres questions similaires, mais les réponses parlaient souvent du fait que les descripteurs de fichiers étaient le coupable (dans ce cas, ils ne le sont pas), en ajoutant plus RAM au système (je ne peux pas le faire), en passant à x64 (Je suis déjà sur x64.) Quelques indices sur le problème d'ENOMEM. Quelques réponses mentionnent essayer de déterminer si le sous-processus. Open (dans mon cas check_output) ne nettoie pas correctement les processus, mais il ressemble à S. Lott et à d'autres convenir que le code du sous-processus lui-même se nettoie correctement.

J'ai cherché dans le code source sur github https://github.com/paramiko/paramiko/search?q=Popen&type=Code et il semble utiliser un sous-processus dans le fichier proxy.py.

Questions réelles

Cela signifie-t-il qu'en fin de compte, paramiko utilise la solution Popen décrite ci-dessus qui rencontrera des problèmes lorsque l'empreinte mémoire python augmente et que des appels Popen répétés sont effectués en raison de l'implémentation clone/fork?

Si paramiko ne fonctionne pas, existe-t-il une autre façon de faire ce que je recherche avec une solution côté client uniquement? Ou une solution client/serveur/socket sera-t-elle nécessaire? Si c'est le cas pour rfoo, tornado ou zeromq, les transferts http fonctionneront ici?

Remarques J'utilise la mémoire principale de 8 Go de Linux 64 bits. Je ne veux pas poursuivre les options d'achat de plus de RAM.

36
Paul

Si vous manquez de mémoire, vous souhaiterez peut-être augmenter votre mémoire de swap. Ou vous pourriez n'avoir aucun échange activé. Dans Ubuntu (cela devrait également fonctionner pour d'autres distributions), vous pouvez vérifier votre échange en:

$Sudo swapon -s

s'il est vide, cela signifie que vous n'avez aucun échange activé. Pour ajouter un swap de 1 Go:

$Sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$Sudo mkswap /swapfile
$Sudo swapon /swapfile

Ajoutez la ligne suivante à fstab pour rendre le swap permanent.

$Sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

La source et plus d'informations peuvent être trouvées ici .

52
Nima

Si vous manquez de mémoire, c'est probablement parce que le sous-processus essaie de lire trop en mémoire en même temps. La solution, autre que l'utilisation d'une redirection vers un fichier local, consiste probablement à utiliser une fonctionnalité de type popen avec une paire stdin/stdout qui peut être lue un peu à la fois.

2
dstromberg

Cela devrait le faire:

http://docs.python.org/3.3/library/subprocess.html#replacing-os-popen-os-popen2-os-popen

De cette façon, vous pouvez lire des lignes ou des blocs, au lieu de la chose entière à la fois.

1
dstromberg