我将标准输出重定向到记录器,现在我使用multiprocessing.Process生成了一个进程。但是,即使将进程stdout重定向到父stdout,它也会忽略sys.stdout覆盖。这是一个示例:
import multiprocessing
import sys
import logging
def worker():
print('Hello from the multiprocessing')
sys.stdout.flush()
class LoggerWriter:
def __init__(self, logger, level):
self.logger = logger
self.level = level
def write(self, message):
if message != '\n':
self.logger.log(self.level, "LOGGER: "+message)
def flush(self):
pass
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, format='%(message)s')
sys.stdout = LoggerWriter(logging.getLogger(), logging.INFO)
p = multiprocessing.Process(target=worker)
print("Hello from main")
p.start()
p.join()
我希望它能打印
LOGGER: Hello from main
LOGGER: Hello from the multiprocessing
但是我得到
LOGGER: Hello from main
Hello from the multiprocessing
它完全忽略了sys.stdout ...为什么?第一种情况可以解决吗?
注意:这是在Windows 7上-似乎可能起作用。
答案 0 :(得分:1)
您使用的是Windows,因此您正在使用spawn方法来启动多处理工作程序。此方法从头开始全新的Python解释器,并在开始工作之前将脚本作为模块导入。
由于您的工作人员是从头开始,而不是从头开始,因此他们不会自动继承主流程执行的设置,包括像stdout包装程序这样的设置,并且由于它们位于{{1} }后卫。他们只有常规的if __name__ == '__main__'
。
您可能必须安排工作人员设置自己的标准输出包装程序,也许是将包装程序设置放在sys.stdout
防护程序之外。
答案 1 :(得分:0)
基于评论和@ user2357112的回答,我最终使用了threading.Thread来处理子进程(通过Queue交换)中的日志,而仍然使用Process进行实际工作。这是为了防止有人需要类似的东西。
基本添加之后:
class LoggedProcess(multiprocessing.Process):
class LoggerWriter:
def __init__(self, queue):
self.queue = queue
def write(self, message):
for line in message.rstrip().splitlines():
self.queue.put(line.rstrip())
def flush(self):
pass
@staticmethod
def logged_worker(logger_queue, worker, *args, **kwargs):
import sys
sys.stdout = sys.stderr = LoggedProcess.LoggerWriter(logger_queue)
logging.basicConfig(format="%(message)s", level=logging.INFO)
try:
worker(*args, **kwargs)
except:
pass
logger_queue.put(None)
@staticmethod
def process_logger(process, logger_queue, name):
while True:
try:
if not process.is_alive():
raise EOFError()
msg = logger_queue.get(timeout=1)
if msg is None:
raise EOFError()
logging.getLogger().log(logging.INFO, f"[PROCESS {process.pid} {name}] {msg}")
except queue.Empty:
pass # timeout
except Exception:
break # queue closed
def __init__(self, target, log_name='', args=(), kwargs={}):
self.logger_queue = multiprocessing.Queue()
self.log_name = log_name
super().__init__(target=self.logged_worker, args=(self.logger_queue, target, *args), kwargs=kwargs)
def start(self):
super().start()
logger_t = threading.Thread(target=self.process_logger, args=(self, self.logger_queue, self.log_name))
logger_t.setDaemon(True)
logger_t.start()
def terminate(self):
super().terminate()
super().join()
self.logger_queue.put(None)
我们可以将p = multiprocessing.Process(target=worker)
替换为p = LoggedProcess(target=worker)
。现在,子进程日志被混合到父进程记录器中,在这种情况下,会导致
LOGGER: Hello from main
[PROCESS 5000 ] Hello from the multiprocessing
我已经添加了一些其他流程信息,但是原始意图仍然可以满足,现在,它可以例如由父流程将其全部放入相同的单个日志文件中,或者需要执行任何其他操作。