Tom*_*Tom 28 python windows stdout multiprocessing stderr
NB.我已经看到了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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后创建并运行如下所示的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()
Run Code Online (Sandbox Code Playgroud)
为了看到与我相同的行为,可能需要针对与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
Run Code Online (Sandbox Code Playgroud)
文件stdout_redirect_log.txt最终包含:
Writing to STDOUT from python, after redirect
Run Code Online (Sandbox Code Playgroud)
换句话说,设置sys.stdout无法重定向DLL生成的stdout输出.鉴于Windows中stdout重定向的基础API的性质,这并不令人惊讶.我以前在本机/ C++级别遇到过这个问题,但从未找到一种方法可以在进程内可靠地重定向stdout.它必须在外部完成.
这实际上是我启动子进程的原因 - 这样我就可以从外部连接到它的管道,从而保证我可以拦截它的所有输出.我可以通过使用pywin32手动启动进程来实现这一点,但我非常希望能够使用多处理功能,特别是通过多处理Pipe对象与子进程通信的能力,以便获得进步更新.问题是,是否有任何方法既可以为其IPC工具使用多处理,又可以将所有子项的stdout和stderr输出可靠地重定向到文件.
更新:查看multiprocessing.Processs的源代码,它有一个静态成员_Popen,看起来它可以用来覆盖用于创建进程的类.如果它设置为None(默认值),它使用multiprocessing.forking._Popen,但它看起来像是说
multiprocessing.Process._Popen = MyPopenClass
Run Code Online (Sandbox Code Playgroud)
我可以覆盖流程创建.然而,虽然我可以从multiprocessing.forking._Popen中得到这个,但看起来我必须将一堆内部东西复制到我的实现中,这听起来很脆弱,而且不太适合未来.如果这是唯一的选择我认为我可能会用pywin32手动完成整个事情.
您建议的解决方案是一个很好的解决方案:手动创建您的流程,以便您可以显式访问其stdout/stderr文件句柄.然后,您可以创建一个套接字以与子进程通信,并在该套接字上使用multiprocessing.connection(multiprocessing.Pipe创建相同类型的连接对象,因此这应该为您提供所有相同的IPC功能).
这是一个双文件示例.
master.py:
import multiprocessing.connection
import subprocess
import socket
import sys, os
## Listen for connection from remote process (and find free port number)
port = 10000
while True:
try:
l = multiprocessing.connection.Listener(('localhost', int(port)), authkey="secret")
break
except socket.error as ex:
if ex.errno != 98:
raise
port += 1 ## if errno==98, then port is not available.
proc = subprocess.Popen((sys.executable, "subproc.py", str(port)), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
## open connection for remote process
conn = l.accept()
conn.send([1, "asd", None])
print(proc.stdout.readline())
Run Code Online (Sandbox Code Playgroud)
subproc.py:
import multiprocessing.connection
import subprocess
import sys, os, time
port = int(sys.argv[1])
conn = multiprocessing.connection.Client(('localhost', port), authkey="secret")
while True:
try:
obj = conn.recv()
print("received: %s\n" % str(obj))
sys.stdout.flush()
except EOFError: ## connection closed
break
Run Code Online (Sandbox Code Playgroud)
您可能还希望看到此问题的第一个答案,以从子进程获取非阻塞读取.
| 归档时间: |
|
| 查看次数: |
12765 次 |
| 最近记录: |