簡體   English   中英

如何啟動進程並將其放入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"

從我的python代碼調用bash腳本。 這種解決方法很完美但我寧願在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

上面的問題是,服務器仍然是Python進程的子進程,可能會收到不需要的信號,如SIGHUP。 如果要使其成為守護程序,則必須首先啟動下一個啟動服務器的子進程。 這樣,當第一個子節點結束時,它可以被調用者等待,服務器將獲得PPID為1(由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()

當文件對象本身是一次返回一行的迭代器時,人們可能想知道對getlines生成器的需求是什么。 問題是,當文件未連接到終端時,它內部調用read直到EOF的讀取。 因為它現在連接到PIPE,所以在服務器結束之前你不會得到任何東西......這不是預期的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM