2013-05-02 8 views
9

Znalazłem wiele podobnych pytań z pytaniem o rozmiar obiektu w czasie wykonywania w python. Niektóre z odpowiedzi sugerują ustawienie limitu pamięci podprocesu. Nie chcę ustawiać limitu pamięci dla podprocesów. Oto, czego chcę -Python - Limit ilości podprocesu danych.Popen może produkować

Używam subprocess.Popen() do uruchomienia zewnętrznego programu. Mogę, bardzo dobrze, uzyskać standardowe wyjście i błąd z process.stdout.readlines() i process.stderr.readlines() po zakończeniu procesu.

Mam problem, gdy błędny program dostaje się do nieskończonej pętli i generuje wydruki. Ponieważ subprocess.Popen() przechowuje dane wyjściowe w pamięci, ta nieskończona pętla szybko pochłania całą pamięć, a program zwalnia.

Jednym z rozwiązań jest to, że mogę uruchomić polecenie z limitem czasu. Ale ukończenie programów zajmuje dużo czasu. Duży czas oczekiwania na program, który zajmuje mało czasu i posiadający nieskończoną pętlę, pokonuje cel jego posiadania.

Czy istnieje prosty sposób, w którym można umieścić górny limit powiedzieć 200MB na ilość danych, które polecenie może produkować? Jeśli przekroczy limit, powinno zostać zabite.

+0

Po zapełnieniu bufora potoku proces potomny nie zwalnia. Zatrzymuje się całkowicie, dopóki nie przeczytasz danych. Jeśli chcesz jednocześnie czytać więcej niż jedną potokę, możesz użyć wątków lub modułów 'select' lub' fcntl' do odczytu rur bez blokowania. – jfs

Odpowiedz

4

Po pierwsze: to nie jest subprocess.Popen() przechowywanie danych, ale jest to fuzja między podprocesami "nas" i "nasz".

W tym przypadku nie powinieneś używać readlines(), ponieważ spowoduje to buforowanie danych na czas nieokreślony i tylko na końcu zwróci je jako listę (w tym przypadku to właśnie ta funkcja przechowuje dane).

Jeśli zrobisz coś podobnego

bytes = lines = 0 
for line in process.stdout: 
    bytes += len(line) 
    lines += 1 
    if bytes > 200000000 or lines > 10000: 
     # handle the described situation 
     break 

można działać jak chciał w swoim pytaniu. Ale nie powinieneś zapominać o zabiciu podprocesu później, aby zatrzymać tworzenie dalszych danych.

Ale jeśli chcesz zadbać o numer stderr, musisz spróbować zreplikować zachowanie process.communicate() za pomocą select() itd. I postępować właściwie.

+3

Krótka uwaga: jeśli zrobisz 'break' wewnątrz twojego' if bytes ... or lines ...: ', w tym przykładzie zatrzymasz" zużywanie "danych z potoku, a twój podproces blokuje próbę napisz do pełnej rury stdout. W tym momencie należy kontynuować konsumpcję (i odrzucić) dane lub zabić proces potomny. – fmoo

+0

@fmoo Całkowicie rację. Konsumpcja i odrzucanie danych może się wydłużyć, ponieważ podproces może znajdować się w nieskończonej pętli, ale zabicie go wydaje się właściwe. – glglgl

+0

może się nie powieść, jeśli OP musi przeczytać również 'stderr'. Jeśli proces potomny wypełni bufor rury stderr, wówczas bloki macierzyste na zawsze próbują odczytać z procesu.stdout' podczas gdy proces potomny próbuje zapisać na jego stderr. – jfs

1

Nie wydaje się być łatwym odpowiedź na to, co chcesz

http://linux.about.com/library/cmd/blcmdl2_setrlimit.htm

rlimit ma flagę w celu ograniczenia pamięci, procesora lub liczbę otwartych plików, ale najwyraźniej nic, aby ograniczyć ilość I/O.

Powinieneś obsługiwać skrzynkę ręcznie, jak już opisano.