1. 程式人生 > >python popen.stdout.read阻塞 解決辦法

python popen.stdout.read阻塞 解決辦法

需求:利用python的subprocess模組結合logging模組實現監控子程式執行情況

程式碼如下(程式阻塞在stdout.readz這裡,日誌裡找不到hang on...................):

import os
import sys
import time
import subprocess
import logging
from logging.handlers import RotatingFileHandler

todaylog = time.strftime('%Y-%m-%d', time.localtime(time.time())).decode('utf-8')
LOG_PATH_FILE = "C:\my.log"
LOG_MODE = 'a'
LOG_MAX_SIZE = 10 * 1024 * 1024  # 10M per file
LOG_MAX_FILES = 10  # 10 Files: my.1, my.2, ...
LOG_LEVEL = logging.DEBUG

LOG_FORMAT = "%(asctime)s %(levelname)-10s[%(filename)s:%(lineno)d(%(funcName)s)] %(message)s"

handler = RotatingFileHandler(LOG_PATH_FILE, LOG_MODE, LOG_MAX_SIZE, LOG_MAX_FILES)
formatter = logging.Formatter(LOG_FORMAT)
handler.setFormatter(formatter)

Logger = logging.getLogger()
Logger.setLevel(LOG_LEVEL)
Logger.addHandler(handler)

pid = os.getpid()


def print_error(s):
    print '\033[31m[%d: ERROR] %s\033[31;m' % (pid, s)


def print_info(s):
    print '\033[32m[%d: INFO] %s\033[32;m' % (pid, s)


def print_warning(s):
    print '\033[33m[%d: WARNING] %s\033[33;m' % (pid, s)


def start_child_proc(command):
    try:
        if command is None:
            raise OSError, "Invalid command"
        
        #Logger.info("def start_child_proc(command, merged):")
        child = None
        child = subprocess.Popen(command, stdout=subprocess.PIPE)
        return child
    except subprocess.CalledProcessError:
        pass  # handle errors in the called executable
    except OSError:
        raise OSError, "Failed to run command!"


def run_forever(command):
    #print_info("start child process with command: " + ' '.join(command))
    Logger.info("start child process with command: " + ' '.join(command))

    child = start_child_proc(command)
    failover = 0

    while True:
        while child.poll() != None:
            failover = failover + 1
            #print_warning("child process shutdown with return code: " + str(child.returncode))
            Logger.critical("child process shutdown with return code: " + str(child.returncode))

            Logger.info('------------------------------------------')
            #print_warning("restart child process again, times=%d" % failover)
            Logger.info("restart child process again, times=%d" % failover)
            child = start_child_proc(command)
        # read child process stdout and log it
        ch = child.stdout.read()
        print "hang on..................."
        Logger.info("hang on...................")
        if ch != '':
            chlist = ch.split('\n')
        for chline in chlist:
            Logger.info(chline)

    Logger.exception("!!!should never run to this!!!")


if __name__ == "__main__":
    run_forever(['python', 'test.py'])

為什麼有時候能夠正常執行,有時候會阻塞?查詢資料找到相關解釋:

還有Stack Overflow上的解釋:

如何解決呢?為了防止這種情況的發生,統一使用out, err = child.communicate()代替read()