78

在 python 中使用 multiprocessing.Process 类时,有没有办法记录给定 Process 的 stdout 输出?

4

5 回答 5

64

最简单的方法可能是覆盖sys.stdout. 稍微修改多处理手册中的示例:

from multiprocessing import Process
import os
import sys

def info(title):
    print title
    print 'module name:', __name__
    print 'parent process:', os.getppid()
    print 'process id:', os.getpid()

def f(name):
    sys.stdout = open(str(os.getpid()) + ".out", "w")
    info('function f')
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    q = Process(target=f, args=('fred',))
    q.start()
    p.join()
    q.join()

并运行它:

$ ls
m.py
$蟒蛇m.py
$ ls
27493.out 27494.out m.py
$ 猫 27493.out
函数 f
模块名称:__main__
父进程:27492
进程号:27493
你好鲍勃
$ 猫 27494.out
函数 f
模块名称:__main__
父进程:27492
进程号:27494
你好弗雷德

于 2009-10-01T03:30:09.967 回答
21

我只会在@Mark Rushakoff 的回答中添加两件事。buffering在调试时,我发现将调用的参数更改open()为 0 非常有用。

sys.stdout = open(str(os.getpid()) + ".out", "a", buffering=0)

否则,疯狂,因为在tail -f输出文件时,结果可能是间歇性的。非常棒buffering=0tail -f

为了完整起见,请帮自己一个忙并重定向sys.stderr

sys.stderr = open(str(os.getpid()) + "_error.out", "a", buffering=0)

此外,为方便起见,如果您愿意,您可以将其转储到单独的进程类中,

class MyProc(Process):
    def run(self):
        # Define the logging in run(), MyProc's entry function when it is .start()-ed 
        #     p = MyProc()
        #     p.start()
        self.initialize_logging()

        print 'Now output is captured.'

        # Now do stuff...

    def initialize_logging(self):
        sys.stdout = open(str(os.getpid()) + ".out", "a", buffering=0)
        sys.stderr = open(str(os.getpid()) + "_error.out", "a", buffering=0)

        print 'stdout initialized'

这是一个相应的要点

于 2014-05-29T15:51:01.913 回答
12

您可以设置sys.stdout = Logger()whereLogger是一个类,其write方法(立即或累积直到\n检测到 a)调用logging.info(或您想要记录的任何其他方式)。这方面的一个例子。

我不确定您所说的“给定”流程是什么意思(谁给定的,它与所有其他流程的区别是什么……?),但如果您的意思是您知道您当时想以这种方式挑出哪个流程实例化它,然后您可以将其target功能(并且仅此功能)- 或run您在Process子类中覆盖的方法 - 包装到执行此 sys.stdout “重定向”的包装器中 - 并保留其他进程。

也许如果您确定一下规格,我可以提供更详细的帮助...?

于 2009-10-01T03:29:57.173 回答
3

这是为 multiprocessing.Processio.TextIOWrapper捕获标准输出的简单直接的方法:

import app
import io
import sys
from multiprocessing import Process


def run_app(some_param):
    out_file = open(sys.stdout.fileno(), 'wb', 0)
    sys.stdout = io.TextIOWrapper(out_file, write_through=True)
    app.run()

app_process = Process(target=run_app, args=('some_param',))
app_process.start()
# Use app_process.termninate() for python <= 3.7.
app_process.kill() 
于 2020-06-26T07:48:42.930 回答
1

log_to_stderr() 函数是最简单的解决方案。

来自PYMOTW

multiprocessing 有一个方便的模块级函数来启用日志记录,称为 log_to_stderr()。它使用日志记录设置一个记录器对象并添加一个处理程序,以便将日志消息发送到标准错误通道。默认情况下,日志记录级别设置为 NOTSET,因此不会生成任何消息。传递不同的级别以将记录器初始化为所需的详细级别。

import logging
from multiprocessing import Process, log_to_stderr

print("Running main script...")

def my_process(my_var):
    print(f"Running my_process with {my_var}...")

# Initialize logging for multiprocessing.
log_to_stderr(logging.DEBUG)

# Start the process.
my_var = 100;
process = Process(target=my_process, args=(my_var,))
process.start()
process.kill()

此代码会将两个 print() 语句都输出到 stderr。

于 2021-02-10T06:51:28.097 回答