当前位置: 首页 > 面试题库 >

Python多处理:如何可靠地从子进程重定向stdout?

卫彭亮
2023-03-14
问题内容

注意
我已经看到了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生成的stdout输出。鉴于Windows中用于stdout重定向的基础API的性质,这不足为奇。我以前在native
/ C ++级别遇到过此问题,但从未找到一种可靠地从进程内重定向stdout的方法。它必须在外部完成。

实际上,这就是我启动子进程的原因-
这样我就可以从外部连接到其子管道,从而保证截获其所有输出。我绝对可以通过使用pywin32手动启动该过程来做到这一点,但是我非常希望能够使用多处理的功能,特别是能够通过多处理Pipe对象与子进程进行通信的能力,从而获得进展。更新。问题是,是否有任何办法既可以对其IPC设施使用多重处理
可以可靠地将孩子的所有stdout和stderr输出重定向到文件。

更新:
查看multiprocessing.Processs的源代码,它有一个静态成员_Popen,看起来它可以用来覆盖用于创建进程的类。如果将其设置为None(默认值),则使用multiprocessing.forking._Popen,但看起来像这样

multiprocessing.Process._Popen = MyPopenClass

我可以覆盖流程创建。但是,尽管我可以从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())

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

您可能还希望看到此问题的第一个答案,以从子流程中进行非阻塞读取。



 类似资料:
  • 问题内容: 我正在尝试使用Tkinter GUI启动子进程并将其stdout / stderr输出显示到Text小部件。最初,我认为可以通过设置“ sys.stdout = text_widget”轻松将sys.stdout重定向到Text小部件,但似乎不行。出现错误:“文本实例没有属性’flush’”。 我在线检查并得到了一些解决方案,例如使用队列与子进程进行通信。但是,由于我的特殊要求,它们都

  • 问题内容: 我想并行化我的Python程序,以便它可以在运行它的机器上使用多个处理器。我的并行化非常简单,程序的所有并行“线程”都是独立的,并将其输出写入单独的文件。我不需要线程交换信息,但是必须知道线程何时完成,因为管道的某些步骤取决于它们的输出。 可移植性很重要,因为我希望它可以在Mac,Linux和Windows上的任何Python版本上运行。考虑到这些限制,哪个是实现此功能的最合适的Pyt

  • 问题内容: 我在命令行中执行的操作: 我想用python做什么: 问题答案: 更新:不鼓励使用,尽管在Python 3中仍然可用。 用途 如果你确实要使用子流程,请使用以下解决方案(大部分内容来自子流程的文档): OTOH,你可以完全避免系统调用:

  • 我使用的是Python 3.5多处理应用异步。我的代码类似于。我在args中传递一个信息(来自信息的对象)。它有一个名为startTime的数据成员。我希望当myFunc开始运行时,将被写入时间。时间()。问题是主流程中的信息和子流程中的信息不一样<代码>信息。开始时间=时间。myFunc中的time()不会更改主进程中的信息。有没有一个好办法来挽救startTime?谢谢

  • 问题内容: 我正在学习如何使用Python多处理库。但是,当我浏览一些示例时,最终我在后台运行了许多python进程。 其中的例子看起来象下面这样: 现在,这是我的“ TOP”命令的屏幕截图: 我不知道如何一口气杀死他们。 ps … | grep python ....杀死吗? 我需要添加哪种python代码,以避免再次发生这种悲惨的情况。谢谢! 问题答案: 您需要在工作队列中处理您的进程,该进程

  • 我使用supervisord作为Docker容器的入口点,如https://docs.Docker.com/articles/using_supervisord/中所述,我希望所有日志都写入stdout,这样我就可以利用内置工具,如或systemd的日志,特别是在CoreOS上运行容器时。 对于stderr,子进程有选项,是否可以以某种方式将子进程stdout重定向回supervisord,而不处