NB. He visto Log output of multiprocessing.Process - lamentablemente, no responde esta pregunta.Multiprocesamiento Python: ¿Cómo puedo redireccionar FIABLY stdout de un proceso hijo?
Estoy creando un proceso secundario (en Windows) a través de multiprocesamiento. Quiero de la salida stdout y stderr del proceso secundario para ser redirigido a un archivo de registro, en lugar de aparecer en la consola. La única sugerencia que he visto es que el proceso secundario establezca sys.stdout en un archivo. Sin embargo, esto no redirige efectivamente todos los resultados de stdout, debido al comportamiento de la redirección stdout en Windows.
Para ilustrar el problema, construir un archivo DLL de Windows con el siguiente código
#include <iostream>
extern "C"
{
__declspec(dllexport) void writeToStdOut()
{
std::cout << "Writing to STDOUT from test DLL" << std::endl;
}
}
A continuación, crear y ejecutar un script en Python, como la siguiente, que importa esta DLL y llama a la función:
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()
Para ver el mismo comportamiento que yo, probablemente sea necesario que la DLL se construya en un tiempo de ejecución de C diferente del que utiliza Python. En mi caso, pitón se construye con Visual Studio 2010, pero mi DLL está construido con VS 2005.
El comportamiento que veo es que la consola muestra:
> stdout_test.py
Writing to STDOUT from python, before redirect
Writing to STDOUT from test DLL
Mientras que el archivo termina stdout_redirect_log.txt que contiene:
Writing to STDOUT from python, after redirect
En otras palabras, el establecimiento de sys.stdout no pudo redirigir la salida stdout generada por el DLL. Esto no es sorprendente dada la naturaleza de las API subyacentes para la redirección stdout en Windows. He encontrado este problema en el nivel nativo/C++ antes y nunca he encontrado una manera de redirigir de manera confiable stdout desde dentro de un proceso. Tiene que hacerse externamente.
Esta es realmente la razón por la que estoy iniciando un proceso secundario, es para poder conectarme externamente a sus tuberías y así garantizar que estoy interceptando toda su salida. Definitivamente puedo hacer esto iniciando el proceso manualmente con pywin32, pero me gustaría mucho poder utilizar las funciones de multiprocesamiento, en particular la capacidad de comunicarme con el proceso hijo a través de un objeto Pipe de multiprocesamiento, para poder avanzar actualizaciones. La pregunta es si hay alguna forma de utilizar el multiprocesamiento para sus instalaciones IPC y para redirigir de manera confiable toda la salida stdout y stderr del niño a un archivo.
ACTUALIZACIÓN: Si examina el código fuente para multiprocessing.Processs, que tiene un miembro estático, _popen, que parece que se puede utilizar para sustituir la clase utilizada para crear el proceso. Si se establece en Ninguno (predeterminado), se utiliza un multiprocessing.forking._Popen, pero parece que al decir
multiprocessing.Process._Popen = MyPopenClass
que podría anular el proceso de creación. Sin embargo, aunque podría derivar esto de multiprocessing.forking._Popen, parece que tendría que copiar un montón de cosas internas en mi implementación, que suena escamosa y no muy a prueba de futuro. Si esa es la única opción, creo que probablemente me gustaría hacer todo manualmente con pywin32.
¿Se puede usar la API de Win32 para iniciar el subproceso, o tiene que hacerse con las bibliotecas de Python existentes? –
Sí, mencioné en la pregunta que "definitivamente puedo hacer esto iniciando el proceso manualmente con pywin32". Parecía una pena abandonar el módulo de multiprocesamiento independiente de la plataforma de nivel superior debido a lo que parece ser una pequeña parte de la funcionalidad que falta: la capacidad de especificar los controladores stdin/stdout para el niño. – Tom
El enfoque que estoy tomando (a menos que a alguien se le ocurra una mejor alternativa) es iniciar el proceso a través del módulo de subproceso, con stdin/stdout redirigido a un archivo y usar un canal nativo de Windows para la comunicación de progreso. – Tom