2013-05-13 23 views
22

Używam podprocesu do wywoływania innego programu i zapisywania jego wartości zwracanych do zmiennej. Proces ten jest powtarzany w pętli, a po kilku tysięcy razy program rozbił się z powodu następującego błędu:Podprocesing w Pythonie: zbyt wiele otwartych plików

Traceback (most recent call last): 
    File "./extract_pcgls.py", line 96, in <module> 
    SelfE.append(CalSelfEnergy(i)) 
    File "./extract_pcgls.py", line 59, in CalSelfEnergy 
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 
    File "/usr/lib/python3.2/subprocess.py", line 745, in __init__ 
    restore_signals, start_new_session) 
    File "/usr/lib/python3.2/subprocess.py", line 1166, in _execute_child 
    errpipe_read, errpipe_write = _create_pipe() 
OSError: [Errno 24] Too many open files 

Każdy pomysł jak rozwiązać ten problem jest bardzo mile widziana!

Kod dostarczany z komentarzy:

cmd = "enerCHARMM.pl -parram=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1]) 
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 
out, err = p.communicate() 
+1

Communicate() zamyka rurę, więc to nie jest twój problem. Ostatecznie, Popen() jest po prostu poleceniem, które uruchamia się, gdy zabraknie rur ... problem może być gdzie indziej w twoim kodzie, a inne pliki pozostaną otwarte. Zauważyłem "SelfE.append" ... czy otwierasz inne pliki i trzymasz je na liście? – tdelaney

Odpowiedz

10

Myślę, że problemem było to spowodowane faktem, że byłem przetwarzanie otwarty plik z podprocesorem:

cmd = "enerCHARMM.pl -par param=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1]) 
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 

Tutaj cmd varia ble zawiera nazwę pliku, który właśnie został utworzony, ale nie został zamknięty. Następnie subprocess.Popen wywołuje polecenie systemowe dla tego pliku. Po wykonaniu tej czynności wiele razy program zawiesił się z tym komunikatem o błędzie.

Więc wiadomość dowiedziałem z tego jest

Close the file you have created, then process it

Dzięki

3

Możesz podnieść otwartą granicę plików systemu operacyjnego:

ulimit -n 2048

+4

W rzeczywistości to polecenie nie podniesie limitu ponad to, co zostało ustawione w '/ etc/security/limits.conf'. Aby go podnieść, musisz umieścić w tym pliku wiersze takie jak '' soft nofile 4096'/'* hard nofile 4096' (zastąp' 4096' własną wartością). –

+1

Zrobiłem wczoraj ten problem i musiałem edytować oba '/ etc/security/limits.conf' i podnieść limit przez' ulimit -n' w Ubuntu, aby pokonać ten błąd. –

0

otwiera plik w podproces. Blokuje połączenie.

ss=subprocess.Popen(tempFileName,shell=True) 
ss.communicate() 
15

W Mac OSX (El Capitan) Zobacz aktualną konfigurację:

#ulimit -a 
core file size   (blocks, -c) 0 
data seg size   (kbytes, -d) unlimited 
file size    (blocks, -f) unlimited 
max locked memory  (kbytes, -l) unlimited 
max memory size   (kbytes, -m) unlimited 
open files      (-n) 256 
pipe size   (512 bytes, -p) 1 
stack size    (kbytes, -s) 8192 
cpu time    (seconds, -t) unlimited 
max user processes    (-u) 709 
virtual memory   (kbytes, -v) unlimited 

Set otwierać pliki wartości do 10K:

#ulimit -Sn 10000 

Wyniki sprawdzenia:

#ulimit -a 

core file size   (blocks, -c) 0 
data seg size   (kbytes, -d) unlimited 
file size    (blocks, -f) unlimited 
max locked memory  (kbytes, -l) unlimited 
max memory size   (kbytes, -m) unlimited 
open files      (-n) 10000 
pipe size   (512 bytes, -p) 1 
stack size    (kbytes, -s) 8192 
cpu time    (seconds, -t) unlimited 
max user processes    (-u) 709 
virtual memory   (kbytes, -v) unlimited 
4

Proces potomny utworzony przez Popen() może dziedziczyć otwarte deskryptory plików (zasób skończony) od elementu nadrzędnego. Użyj close_fds=True na POSIX (domyślnie od Python 3.2), aby tego uniknąć. Ponadto, "PEP 0446 -- Make newly created file descriptors non-inheritable" deals with some remaining issues (since Python 3.4).

+0

Nie sądzę, że to działa, przynajmniej we wszystkich przypadkach. Wygenerowałem 1200 odrodzonych procesów snu w systemie z 1024 limitem otwartego pliku (domyślnie w systemie Ubuntu) i dmgło nawet z close_fds = True. Myślę więc, że jest w tym coś więcej. Ponieważ i tak masz nadal ponad limit w otwartych procesach, a to działa tylko wtedy, gdy założysz, że problem leży w zakończeniu procesów, które pozostawiły otwarte deskryptory plików. – Sensei

+0

@Sensei to działa: otwórz pliki w rodzica (upewnij się, że fds są dziedziczne), a następnie spawnuj podprocesy za pomocą 'close_fds = False' (oba są domyślne w starych wersjach Pythona, podążaj za odnośnikami). Sprawdź, ile szybciej pojawi się błąd. Oczywiście 'close_fds' nie może zapobiec błędowi w ogólnym przypadku: nie musisz nawet odradzać nowego procesu, aby go uzyskać. – jfs

+0

Tyle tylko, że tak nie jest. Uruchomiłem prostą pętlę for i wygenerowałem wystarczającą ilość podprocesów, aby osiągnąć limit OS. Zrobiłem to z close_fds = True. Nie miało to żadnego wpływu. Mogę się mylić, ale domyślam się, że to rozwiązanie działa tylko wtedy, gdy tworzysz kilka podprocesów i nigdy nie czyścisz deskryptorów. W takim przypadku argument ten ma sens, ale nie widzę, żeby działał, jeśli faktycznie zamierzasz odrodzić się i uruchomić wiele procesów jednocześnie. – Sensei

2

jak inni to zauważyli, podwyższyć limit w /etc/security/limits.conf a także deskryptorów był to problem dla mnie osobiście, więc zrobiłem

sudo sysctl -w fs.file-max=100000 

i dodaje linię fs.file -max = 100000 do /etc/sysctl.conf (przeładować z sysctl -p)

Także jeśli chcesz, aby upewnić się, że proces ten nie ma wpływu na cokolwiek innego (co kopalnia), użyj

cat /proc/{process id}/limits 

znaleźć jakie są rzeczywiste ograniczenia twojego procesu, ponieważ dla mnie oprogramowanie uruchamiające skrypty Pythona miało również swoje ograniczenia, które przesłoniły ustawienia całego systemu.

Umieszczanie tej odpowiedzi tutaj po rozwiązaniu mojego konkretnego problemu z tym błędem i mam nadzieję, że pomaga komuś.

Powiązane problemy