Im folgenden Code versuche ich, einen Prozess zum Ausführen eines Befehls zu verzweigen und dann das Ergebnis zurückzunehmen, wenn der Kind-Subprozess beendet wurde.Wann gibt subprocess.Popen in Python sporadisch None zurück?
Am Ende wird eine Schleife in einer globalen Variablen ausgeführt, um darauf zu warten, dass der untergeordnete Prozess beendet wird, sodass der übergeordnete Prozess nicht vor dem untergeordneten Prozess beendet wird, aber die Ausführung des Befehls insgesamt nicht blockierend ist. Der Code funktioniert gut 9 von 10 mal, aber manchmal gibt es den Fehler.
Fehler ist im Fall, wenn es subprocess.Popen
None
zurück scheint. Aber ich bin mir nicht sicher, warum das zufällig passieren würde.
Kann jemand bitte helfen herauszufinden, was falsch ist hier los?
Maschinendetails
[[email protected] /]# uname -a
Linux 1-0-0-9 3.10.0-229.el7.x86_64 #1 SMP Thu Jan 29 18:37:38 EST 2015 x86_64 x86_64 x86_64 GNU/Linux
Code:
#!/usr/bin/env python
import os
import subprocess
import signal
import time
flag = False
class Utils(object):
def __init__(self):
self.child_pid = None
signal.signal(signal.SIGCHLD, self.sigchld_handler)
def sigchld_handler(self, *args):
print "handling SIGCHLD"
p = self.child_pid
stdout_val = p.communicate()[0]
retcode = p.returncode
print p.returncode, stdout_val.strip()
self.child_pid = None
global flag
flag = False
def run_command(self, cmnd, env=None, cwd=None, timeout=0):
global flag
flag = True
cmnd = cmnd.split()
self.child_pid =subprocess.Popen(cmnd, stdin=None, bufsize=-1, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
close_fds=True, cwd=cwd, preexec_fn=os.setsid)
print "Invoked child process " , self.child_pid.pid
print "Running command .."
Utils().run_command("ls -lrt")
for i in xrange(10000):
if not i % 1000:
print i
print flag
i = 0
while flag:
i = i + 1
Correct (Wunsch) Ausgang:
Running command ..
Invoked child process 9703
0
1000
2000
3000
4000
5000
handling SIGCHLD
0 total 52
drwxr-xr-x. 2 root root 6 Mar 13 2014 srv
drwxr-xr-x. 2 root root 6 Mar 13 2014 mnt
drwxr-xr-x. 2 root root 6 Mar 13 2014 media
drwxr-xr-x. 2 root root 6 Mar 13 2014 home
lrwxrwxrwx. 1 root root 7 Jan 9 2016 bin -> usr/bin
lrwxrwxrwx. 1 root root 9 Jan 9 2016 lib64 -> usr/lib64
lrwxrwxrwx. 1 root root 7 Jan 9 2016 lib -> usr/lib
lrwxrwxrwx. 1 root root 8 Jan 9 2016 sbin -> usr/sbin
drwxr-xr-x. 13 root root 4096 Jan 9 2016 usr
drwxr-xr-x. 4 root root 28 Nov 18 16:03 opt
dr-xr-xr-x. 4 root root 4096 Nov 18 16:06 boot
dr-xr-xr-x 178 root root 0 Nov 22 21:53 proc
dr-xr-xr-x 13 root root 0 Nov 22 21:53 sys
drwxr-xr-x. 22 root root 4096 Nov 22 21:53 var
drwxr-xr-x 19 root root 3060 Nov 22 21:53 dev
drwxr-xr-x. 124 root root 8192 Nov 22 21:53 etc
dr-xr-x---. 8 root root 4096 Nov 22 21:53 root
-rw-r--r-- 1 root root 573 Nov 22 22:15 a.py
-rw-r--r-- 1 root root 1108 Nov 22 22:15 cmnd.py
-rw-r--r-- 1 root root 1800 Nov 22 22:15 fork.py
-rw-r--r-- 1 root root 1368 Nov 22 22:15 ipc_pipe.py
-rw-r--r-- 1 root root 491 Nov 22 22:15 threads.py
drwxr-xr-x 35 root root 1000 Nov 22 22:35 run
drwxrwxrwt. 8 root root 4096 Nov 22 22:35 tmp
6000
7000
8000
9000
False
Fehler (Failing Fall):
Running command ..
handling SIGCHLD
handling SIGCHLD
handling SIGCHLD
Traceback (most recent call last):
File "cmnd.py", line 37, in <module>
Utils().run_command("ls -lrt")
File "cmnd.py", line 33, in run_command
close_fds=True, cwd=cwd, preexec_fn=os.setsid)
File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__
errread, errwrite)
File "/usr/lib64/python2.7/subprocess.py", line 1296, in _execute_child
data = _eintr_retry_call(os.read, errpipe_read, 1048576)
File "/usr/lib64/python2.7/subprocess.py", line 478, in _eintr_retry_call
return func(*args)
File "cmnd.py", line 19, in sigchld_handler
stdout_val = p.communicate()[0]
AttributeError: 'NoneType' object has no attribute 'communicate'
Interessanterweise wurde "Handling SIGCHLD" einige Male gedruckt. Es gab nur einen Prozess gespalten, also warum sollte Elternprozess SIGCHLD 3 Mal erhalten? – ViFI
Nicht sicher, aber ich denke, dass Sie in eine Race-Bedingung geraten, wo Sie den Child-Prozess spawnen, bevor die Zuordnung des 'Popen'-Objekts zu' self.child_pid' abgeschlossen ist. Ich würde vorschlagen, dass Sie einen anderen Weg finden, etwas zu tun, wenn das Kind fertig ist, zum Beispiel auf seine Ausgabe wartend, vielleicht in einem anderen Thread. – 2rs2ts