如何启动进程并将其置于 python 中的后台?
How can I start a process and put it to background in python?
我目前正在编写我的第一个 python 程序(在 Python 2.6.6 中)。该程序有助于在服务器上启动和停止不同的应用程序 运行,提供用户常用命令(例如在 Linux 服务器上启动和停止系统服务)。
我正在通过
启动应用程序的启动脚本
p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate()
print(output)
问题是,一个应用程序的启动脚本停留在前台,因此 p.communicate() 永远等待。我已经尝试在 startCommand 前面使用 "nohup startCommand &" 但没有按预期工作。
作为解决方法,我现在使用以下 bash 脚本来调用应用程序的启动脚本:
#!/bin/bash
LOGFILE="/opt/scripts/bin/logs/SomeServerApplicationStart.log"
nohup /opt/someDir/startSomeServerApplication.sh >${LOGFILE} 2>&1 &
STARTUPOK=$(tail -1 ${LOGFILE} | grep "Server started in RUNNING mode" | wc -l)
COUNTER=0
while [ $STARTUPOK -ne 1 ] && [ $COUNTER -lt 100 ]; do
STARTUPOK=$(tail -1 logs/SomeServerApplicationStart.log | grep "Server started in RUNNING mode" | wc -l)
if (( STARTUPOK )); then
echo "STARTUP OK"
exit 0
fi
sleep 1
COUNTER=$(( $COUNTER + 1 ))
done
echo "STARTUP FAILED"
bash 脚本是从我的 python 代码中调用的。此解决方法非常有效,但我更愿意在 python...
中完成所有工作
subprocess.Popen是不是走错了?我如何才能在 Python 完成我的任务?
首先,很容易不阻止通信中的 Python 脚本...通过不调用通信!只需从命令的输出或错误输出中读取,直到找到正确的消息并忘记该命令。
# to avoid waiting for an EOF on a pipe ...
def getlines(fd):
line = bytearray()
c = None
while True:
c = fd.read(1)
if c is None:
return
line += c
if c == '\n':
yield str(line)
del line[:]
p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) # send stderr to stdout, same as 2>&1 for bash
for line in getlines(p.stdout):
if "Server started in RUNNING mode" in line:
print("STARTUP OK")
break
else: # end of input without getting startup message
print("STARTUP FAILED")
p.poll() # get status from child to avoid a zombie
# other error processing
上面的问题是,服务器仍然是 child 一个 Python 进程,并且可能会收到不需要的信号,例如 SIGHUP。如果你想让它成为一个守护进程,你必须先启动一个子进程,然后再启动你的服务器。这样当第一个 child 结束时,它可以被调用者等待并且服务器将获得 1 的 PPID(由 init 进程采用)。您可以使用多处理模块来简化该部分
代码可能是这样的:
import multiprocessing
import subprocess
# to avoid waiting for an EOF on a pipe ...
def getlines(fd):
line = bytearray()
c = None
while True:
c = fd.read(1)
if c is None:
return
line += c
if c == '\n':
yield str(line)
del line[:]
def start_child(cmd):
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
shell=True)
for line in getlines(p.stdout):
print line
if "Server started in RUNNING mode" in line:
print "STARTUP OK"
break
else:
print "STARTUP FAILED"
def main():
# other stuff in program
p = multiprocessing.Process(target = start_child, args = (server_program,))
p.start()
p.join()
print "DONE"
# other stuff in program
# protect program startup for multiprocessing module
if __name__ == '__main__':
main()
当一个文件 object 本身就是一个 returns 一次一行的迭代器时,人们可能想知道 getlines
生成器的需求是什么。问题是当文件未连接到终端时,它在内部调用 read
读取直到 EOF。因为它现在连接到一个 PIPE,所以在服务器结束之前你不会得到任何东西......这不是所期望的
我目前正在编写我的第一个 python 程序(在 Python 2.6.6 中)。该程序有助于在服务器上启动和停止不同的应用程序 运行,提供用户常用命令(例如在 Linux 服务器上启动和停止系统服务)。
我正在通过
启动应用程序的启动脚本p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate()
print(output)
问题是,一个应用程序的启动脚本停留在前台,因此 p.communicate() 永远等待。我已经尝试在 startCommand 前面使用 "nohup startCommand &" 但没有按预期工作。
作为解决方法,我现在使用以下 bash 脚本来调用应用程序的启动脚本:
#!/bin/bash
LOGFILE="/opt/scripts/bin/logs/SomeServerApplicationStart.log"
nohup /opt/someDir/startSomeServerApplication.sh >${LOGFILE} 2>&1 &
STARTUPOK=$(tail -1 ${LOGFILE} | grep "Server started in RUNNING mode" | wc -l)
COUNTER=0
while [ $STARTUPOK -ne 1 ] && [ $COUNTER -lt 100 ]; do
STARTUPOK=$(tail -1 logs/SomeServerApplicationStart.log | grep "Server started in RUNNING mode" | wc -l)
if (( STARTUPOK )); then
echo "STARTUP OK"
exit 0
fi
sleep 1
COUNTER=$(( $COUNTER + 1 ))
done
echo "STARTUP FAILED"
bash 脚本是从我的 python 代码中调用的。此解决方法非常有效,但我更愿意在 python...
中完成所有工作subprocess.Popen是不是走错了?我如何才能在 Python 完成我的任务?
首先,很容易不阻止通信中的 Python 脚本...通过不调用通信!只需从命令的输出或错误输出中读取,直到找到正确的消息并忘记该命令。
# to avoid waiting for an EOF on a pipe ...
def getlines(fd):
line = bytearray()
c = None
while True:
c = fd.read(1)
if c is None:
return
line += c
if c == '\n':
yield str(line)
del line[:]
p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) # send stderr to stdout, same as 2>&1 for bash
for line in getlines(p.stdout):
if "Server started in RUNNING mode" in line:
print("STARTUP OK")
break
else: # end of input without getting startup message
print("STARTUP FAILED")
p.poll() # get status from child to avoid a zombie
# other error processing
上面的问题是,服务器仍然是 child 一个 Python 进程,并且可能会收到不需要的信号,例如 SIGHUP。如果你想让它成为一个守护进程,你必须先启动一个子进程,然后再启动你的服务器。这样当第一个 child 结束时,它可以被调用者等待并且服务器将获得 1 的 PPID(由 init 进程采用)。您可以使用多处理模块来简化该部分
代码可能是这样的:
import multiprocessing
import subprocess
# to avoid waiting for an EOF on a pipe ...
def getlines(fd):
line = bytearray()
c = None
while True:
c = fd.read(1)
if c is None:
return
line += c
if c == '\n':
yield str(line)
del line[:]
def start_child(cmd):
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
shell=True)
for line in getlines(p.stdout):
print line
if "Server started in RUNNING mode" in line:
print "STARTUP OK"
break
else:
print "STARTUP FAILED"
def main():
# other stuff in program
p = multiprocessing.Process(target = start_child, args = (server_program,))
p.start()
p.join()
print "DONE"
# other stuff in program
# protect program startup for multiprocessing module
if __name__ == '__main__':
main()
当一个文件 object 本身就是一个 returns 一次一行的迭代器时,人们可能想知道 getlines
生成器的需求是什么。问题是当文件未连接到终端时,它在内部调用 read
读取直到 EOF。因为它现在连接到一个 PIPE,所以在服务器结束之前你不会得到任何东西......这不是所期望的