В следующем коде я пытаюсь разблокировать процесс для запуска команды, а затем забрать результат, когда дочерний подпроцесс вышел.Когда subprocess.Popen возвращает None в Python, спорадически?
В конце цикла в глобальном var выполняется цикл, чтобы дождаться завершения дочернего процесса, чтобы родительский процесс не выходил до дочернего процесса, но общий запуск команды не блокирует в некотором роде. Код работает нормально 9 из 10 раз, но время от времени дает ошибку.
Ошибка на случай, если будет subprocess.Popen
None
. Но я не уверен, почему это произойдет случайно.
Может кто-нибудь помочь в выяснении того, что здесь происходит не так?
детали машины
[[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
Код:
#!/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 (Желаемая) Выход:
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
Error (В противном случае):
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'
Интересно, что «обработка SIGCHLD» печаталась пару раз. Был только один процесс раздвоения, так почему бы родительский процесс получил SIGCHLD 3 раза? – ViFI
Не уверен, но я думаю, что вы столкнулись с условием гонки, когда вы запускаете дочерний процесс до того, как завершается присвоение объекта 'Popen'' self.child_pid'. Я предлагаю вам найти другой способ сделать что-то, когда ребенок закончит, например, ждет на выходе, возможно, в другом потоке. – 2rs2ts