Soru subprocess modülü ile zombi süreçlerini nasıl öldürebilir (veya kaçınılabilir)


Bir altyazı modülünü kullanarak başka bir python betiğinden bir python betiğini başlattığımda, alt işlem "tamamlandığında" bir zombi işlemi oluşturulur. Ebeveyn python sürecimi öldürmediğim sürece bu alt işlemi yapamıyorum.

Ebeveynleri öldürmeden alt süreci öldürmenin bir yolu var mı? Bunu wait () kullanarak yapabileceğimi biliyorum, fakat no_wait () komut dosyasını çalıştırmam gerekiyor.


43
2018-05-03 19:29


Menşei




Cevaplar:


Kullanmıyor Popen.communicate() veya call() bir zombi süreci ile sonuçlanacak.

Komutun çıktısına ihtiyacınız yoksa, kullanabilirsiniz subprocess.call():

>>> import subprocess
>>> subprocess.call(['grep', 'jdoe', '/etc/passwd'])
0

Çıktı önemliyse, kullanmalısınız Popen() ve communicate() stdout ve stderr'i almak için.

>>> from subprocess import Popen, PIPE
>>> process = Popen(['ls', '-l', '/tmp'], stdout=PIPE, stderr=PIPE)
>>> stdout, stderr = process.communicate()
>>> stderr
''
>>> print stdout
total 0
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 bar
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 baz
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 foo

21
2018-05-03 21:11



Yorumun için teşekkürler. Beklenmedik şekilde, iletişim yeni bir tane oluşturmadan önce işlemlerin tamamlanmasını bekler. Sayısal süreçleri paralel olarak çalıştırmam gerek. - Dave
call () işlemin bitmesini bekler. Bence OP, süreçleri doğurmak ve koşarken ana süreçte başka bir şey yapmak istiyor. - ibz
İle Popen.poll() işlemin bitip bitmediğini kontrol edebilir, sonra kullanabilirsiniz communicate. Bu sayede eşzamanlılığı koruyabilirsiniz. - Diego Navarro
Ya arayamazsan? call çünkü sürecin stdinine yazman gerekiyor, ama çıktıyı umursamıyorsun? - Michael
Bir not, Popen çıktısını herhangi bir şekilde kullanırsanız, o zaman zombi işlemi hala oluşturulur. - Roman


Bir zombi süreci gerçek bir süreç değildir; Ebeveyn süreci çocuğun geri dönüş kodunu talep edene kadar işlem tablosunda kalan bir girdidir. Asıl işlem sona erdi ve başka kaynak gerektirmiyor ancak söz konusu süreç tablosu girişi.

Aslında daha fazla yardımcı olabilmek için çalıştırdığınız süreçler hakkında daha fazla bilgiye ihtiyacımız var.

Ancak, Python programınızın olması durumunda bilir Çocuk süreçleri sona erdiğinde (örn. çocuk stdout verilerinin sonuna ulaşarak), güvenli bir şekilde arayabilirsiniz process.wait():

import subprocess

process= subprocess.Popen( ('ls', '-l', '/tmp'), stdout=subprocess.PIPE)

for line in process.stdout:
        pass

subprocess.call( ('ps', '-l') )
process.wait()
print "after wait"
subprocess.call( ('ps', '-l') )

Örnek çıktı:

$ python so2760652.py
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S   501 21328 21326  0  80   0 -  1574 wait   pts/2    00:00:00 bash
0 S   501 21516 21328  0  80   0 -  1434 wait   pts/2    00:00:00 python
0 Z   501 21517 21516  0  80   0 -     0 exit   pts/2    00:00:00 ls <defunct>
0 R   501 21518 21516  0  80   0 -   608 -      pts/2    00:00:00 ps
after wait
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S   501 21328 21326  0  80   0 -  1574 wait   pts/2    00:00:00 bash
0 S   501 21516 21328  0  80   0 -  1467 wait   pts/2    00:00:00 python
0 R   501 21519 21516  0  80   0 -   608 -      pts/2    00:00:00 ps

Aksi halde, tüm çocukları bir listede saklayabilirsin, şimdi ve sonra .poll dönüş kodları için. Her yinelemeden sonra, dönüş kodları farklı olan çocuklar listeden kaldırmayı unutmayın. None (yani bitmiş olanlar).


18
2018-05-03 23:01



Oh, şimdi cevabımın temel olarak son paragrafınızın kod versiyonu olduğunu görüyorum. - Peter Lyons
Zombi süreçleri hakkında çok yararlı bilgiler. Bu bilginin tüm platformlara eşit olarak uygulanıp uygulanmadığını biliyor musunuz? yani, zombi süreçleri sadece girişlerdir ve aslında çalışmıyorlar. - Zoran Pavlovic
@ZoranPavlovic: zombi süreci POSIX'te gerçek bir şey: Çıkış durumu sona erdiğinde ve bu durumun sonlandırılmasını bekleyen başka bir işleme rapor edildiğinde silinmiş olan bir süreç. - jfs
Bu mümkün olsaydı 2 ups verecekti! - nacholibre


Alt işlem nesnesini silerseniz, del Çöp toplama işlemini zorlamak için, alt işlem nesnesinin silinmesine neden olacak ve daha sonra işlem dışı bırakılmış işlemler yorumcunuzu sonlandırmadan sona erecektir. Bunu önce python komut satırı arayüzünde deneyebilirsiniz.


15
2017-10-18 14:20



Bu benim için çalışmadı: s = subprocess.Popen('exec cat /dev/zero > /dev/null'), sonra killall cat sonra del s → zombi hala orada. - MarSoft
Benim için çalıştı. Kerevizde, SoftTimeLimitExceeded istisnası kaldırıldığında s.kill() sonra del s. Zombi yok. - Travis
Bu işe yaramıyor Python 2 - darkfeline


Python çalışma zamanı, süreç nesneleri çöp toplandıktan sonra zombi işleminden kurtulmak için sorumluluk alır. Çevresinde yatan zombi görüyorsanız, bir süreç nesnesini tuttuğunuz ve beklemediğiniz, yoklamadığınız veya üzerinde sonlanmadığı anlamına gelir.


4
2018-06-04 11:20



Basit bir test, Python 2'de doğru olmadığını gösterir.. Python 3 üzerinde çalışıyor gibi görünüyor - jfs
@ J.F.Sebastian Testin doğru olduğundan emin misin? Aramadığınız için .wait(), .poll() veya .terminate()Tahminimce Peter doğru. - blong
@blong: bir yöntemi çağırmak için, bir ad (veya bir nesneyi referans almak için başka bir yol) gerekir: test, kasıtlı olarak açık referanslar tutmaz Popen() nesneler. Bu olup olmadığını test eder "Python çalışma zamanı, süreç nesneleri çöp toplandıktan sonra zombi işleminden kurtulmak için sorumluluk alır". Zombilerle başa çıkmak için biraz destek var: _active liste, _cleanup() işlev denir Popen() ama test, Python 2'de yardımcı olmadığını gösteriyor. - jfs


Sadece kullanırsanız subprocess.Popen, iyi olacaksın - işte nasıl:

import subprocess

def spawn_some_children():
    subprocess.Popen(["sleep", "3"])
    subprocess.Popen(["sleep", "3"])
    subprocess.Popen(["sleep", "3"])

def do_some_stuff():
    spawn_some_children()
    # do some stuff
    print "children went out to play, now I can do my job..."
    # do more stuff

if __name__ == '__main__':
    do_some_stuff()

Kullanabilirsiniz .poll() Popen tarafından iade edilen nesnenin bitip bitmediğini kontrol etmek için (beklemeden). Eğer dönerse None, çocuk hala çalışıyor.

Popen nesnelerine atıfta bulunmadığınızdan emin olun - eğer yaparsanız, çöp toplanmayacaklar, böylece zombiler ile sonuçlanırsınız. İşte bir örnek:

import subprocess

def spawn_some_children():
    children = []
    children.append(subprocess.Popen(["sleep", "3"]))
    children.append(subprocess.Popen(["sleep", "3"]))
    children.append(subprocess.Popen(["sleep", "3"]))
    return children

def do_some_stuff():
    children = spawn_some_children()
    # do some stuff
    print "children went out to play, now I can do my job..."
    # do more stuff

    # if children finish while we are in this function,
    # they will become zombies - because we keep a reference to them

Yukarıdaki örnekte, zombilerden kurtulmak istiyorsanız, ya .wait() her bir çocuk ya da .poll() sonuç alınana kadar None.

Her iki yol da iyidir - referansları tutmamak ya da kullanmak .wait() veya .poll().


3
2017-08-15 09:53



Ebeveyn canlı tutulursa, ilk örneğinizin zombileri üretmediğini kontrol ettiniz mi? - jfs
Harika cevap! Öldürülen sürece yapılan göndermelerin serbest bırakılması bir çekicilik gibi çalıştı. - its me


Ne demek istediğimi anlamadım "Senaryoyu no_wait ()" ile çalıştırmam gerekiyor, ama bence bu örnek neye ihtiyacın var. Süreçler çok uzun süredir zombiler olmayacaktır. Ana işlem sadece wait() Onlarda aslında feshedildikleri zaman ve böylece çabucak anlaşılmayacaklar.

#!/usr/bin/env python2.6
import subprocess
import sys
import time

children = []
#Step 1: Launch all the children asynchronously
for i in range(10):
    #For testing, launch a subshell that will sleep various times
    popen = subprocess.Popen(["/bin/sh", "-c", "sleep %s" % (i + 8)])
    children.append(popen)
    print "launched subprocess PID %s" % popen.pid

#reverse the list just to prove we wait on children in the order they finish,
#not necessarily the order they start
children.reverse()
#Step 2: loop until all children are terminated
while children:
    #Step 3: poll all active children in order
    children[:] = [child for child in children if child.poll() is None]
    print "Still running: %s" % [popen.pid for popen in children]
    time.sleep(1)

print "All children terminated"

Sonuna doğru çıkış şöyle görünüyor:

Still running: [29776, 29774, 29772]
Still running: [29776, 29774]
Still running: [29776]
Still running: []
All children terminated

1
2018-05-08 04:04



Bu çok fazla. Peter'in dediği gibi - Popen nesnesine herhangi bir referans göstermediğinizden emin olmak için yeterlidir ve bununla ilgilenilecektir. Çocuk süreçlerinin bitmesini beklemek istiyorsanız, ankette yalnızca anket () veya wait () kullanmanız gerekir. - ibz
Ayrıca - eğer yapÇocuk süreçlerinin bitmesini beklemek istersiniz, sadece her birinde wait () kullanabilirsiniz - ankete () gerek yok ve listenizden kaldırmanız gerekmez. Her birinde bekle () yapmak sonuncuya kadar beklemenizi sağlar (eğer istediğin buysa). - ibz
@ibz: 1. Popen nesnelerine referans tutmaktan kaçınmak için yeterli değildir. 2. kullanma .wait() zombiler yaratabilir: aradığınızı hayal edin .wait() Bir saat içinde bitmesi gereken bir süreçte ve saniyede çıkması gereken 1000 çocuğunuz daha var. Boom. saniyede 1000 zombileriniz var ve saat geçene kadar yanmayacaksınız. - jfs


Ne demek istediğinden emin değilim no_wait(). Çocuk süreçlerinin bitmesini beklemeyi engelleyemediğiniz anlamına mı geliyor? Öyle sanıyorum, bence istediğini yapacaksın:

os.wait3(os.WNOHANG)

0
2018-05-03 19:36