注意。我看过 multiprocessing.Process 的日志输出- 不幸的是,它没有回答这个问题。
我正在通过多处理创建一个子进程(在 Windows 上)。我希望 将所有 子进程的 stdout 和 stderr 输出重定向到日志文件,而不是出现在控制台上。我看到的唯一建议是让子进程将 sys.stdout 设置为一个文件。但是,由于 Windows 上的 stdout 重定向行为,这并不能有效地重定向所有 stdout 输出。
为了说明问题,使用以下代码构建一个 Windows DLL
#include <iostream>
extern "C"
{
__declspec(dllexport) void writeToStdOut()
{
std::cout << "Writing to STDOUT from test DLL" << std::endl;
}
}
然后创建并运行如下所示的 python 脚本,它导入此 DLL 并调用该函数:
from ctypes import *
import sys
print
print "Writing to STDOUT from python, before redirect"
print
sys.stdout = open("stdout_redirect_log.txt", "w")
print "Writing to STDOUT from python, after redirect"
testdll = CDLL("Release/stdout_test.dll")
testdll.writeToStdOut()
为了看到与我相同的行为,可能需要针对不同于 Python 使用的 C 运行时构建 DLL。在我的例子中,python 是用 Visual Studio 2010 构建的,但我的 DLL 是用 VS 2005 构建的。
我看到的行为是控制台显示:
> stdout_test.py
Writing to STDOUT from python, before redirect
Writing to STDOUT from test DLL
虽然文件 stdout_redirect_log.txt 最终包含:
Writing to STDOUT from python, after redirect
换句话说,设置 sys.stdout 无法重定向 DLL 生成的标准输出输出。考虑到 Windows 中标准输出重定向的底层 API 的性质,这并不奇怪。我以前在本机/C++ 级别遇到过这个问题,但从未找到一种从进程内可靠地重定向 stdout 的方法。它必须在外部完成。
这实际上就是我启动子进程的原因——这样我就可以从外部连接到它的管道,从而保证我正在拦截它的所有输出。我绝对可以通过使用 pywin32 手动启动进程来做到这一点,但我非常希望能够使用多处理的功能,特别是通过多处理 Pipe 对象与子进程通信的能力,以获得进展更新。问题是是否有任何方法既可以为其 IPC 设施使用多处理, 又 可以可靠地将子进程的所有 stdout 和 stderr 输出重定向到一个文件。
更新: 查看 multiprocessing.Processs 的源代码,它有一个静态成员 _Popen,它看起来可以用来覆盖用于创建进程的类。如果它设置为无(默认),它使用 multiprocessing.forking._Popen,但它看起来像说
multiprocessing.Process._Popen = MyPopenClass
我可以覆盖流程创建。然而,虽然我可以从 multiprocessing.forking._Popen 中派生出它,但看起来我必须将一堆内部内容复制到我的实现中,这听起来很不稳定而且不太适合未来。如果那是唯一的选择,我想我可能会选择使用 pywin32 手动完成所有操作。
原文由 Tom 发布,翻译遵循 CC BY-SA 4.0 许可协议
您建议的解决方案是一个很好的解决方案:手动创建您的进程,以便您可以明确访问它们的 stdout/stderr 文件句柄。然后,您可以创建一个套接字来与子进程通信,并在该套接字上使用 multiprocessing.connection(multiprocessing.Pipe 创建相同类型的连接对象,因此这应该为您提供所有相同的 IPC 功能)。
这是一个包含两个文件的示例。
主.py:
子过程.py:
您可能还想查看 此问题 的第一个答案,以从子进程中获取非阻塞读取。