2011-12-06 13 views
5

Tengo un programa posiblemente de larga ejecución que actualmente tiene 4 procesos, pero podría configurarse para tener más. Investigué logging from multiple processes usando python's logging y estoy usando el enfoque SocketHandler discutido here. Nunca tuve problemas para tener un solo registrador (sin sockets), pero por lo que leí me dijeron que fallaría eventualmente e inesperadamente. Por lo que yo entiendo, es desconocido lo que sucederá cuando trates de escribir en el mismo archivo al mismo tiempo. Mi código hace esencialmente lo siguiente:Registro Python desde procesos múltiples

import logging 
log = logging.getLogger(__name__) 

def monitor(...): 
    # Spawn child processes with os.fork() 
    # os.wait() and act accordingly 

def main(): 
    log_server_pid = os.fork() 
    if log_server_pid == 0: 
     # Create a LogRecordSocketServer (daemon) 
     ... 
     sys.exit(0) 
    # Add SocketHandler to root logger 
    ... 
    monitor(<configuration stuff>) 

if __name__ == "__main__": 
    main() 

Así que mis preguntas son: ¿Es necesario crear un nuevo objeto log después de cada os.fork()? ¿Qué ocurre con el objeto global log existente?

Al hacer las cosas como soy, ¿estoy repasando el problema que trato de evitar (varios archivos/sockets abiertos)? ¿Fallará esto y por qué fallará (me gustaría poder decir si las implementaciones similares futuras fallarán)?

Además, ¿de qué manera falla el método "normal" (una expresión log=) de iniciar sesión en un archivo de múltiples procesos? ¿Aumenta un IOError/OSError? ¿O simplemente no escribe completamente los datos en el archivo?

Si alguien pudiera proporcionar una respuesta o enlaces para ayudarme, sería genial. Gracias.

FYI: estoy probando en Mac OS X Lion y el código probablemente terminará ejecuta en una máquina virtual CentOS 6 en una máquina Windows (si lo que importa). Cualquier solución que use no necesita funcionar en Windows, pero debería funcionar en un sistema basado en Unix.

ACTUALIZACIÓN: Esta pregunta ha comenzado a alejarse de la tala comportamiento específico y es más en el ámbito de lo que hace Linux con descriptores de archivos durante horquillas. Saqué uno de mis libros de texto universitarios y parece que si abre un archivo en el modo de adición de dos procesos (no antes de un tenedor), ambos podrán escribir en el archivo correctamente, siempre que su escritura no exceda el búfer real del kernel (aunque es posible que haya que usar el buffer de línea, aún no estoy seguro de eso). Esto crea 2 entradas de tabla de archivos y una entrada de tabla v-node. No se supone que abrir un archivo y bifurcar funcione, pero parece que siempre y cuando no exceda el búfer del núcleo como antes (lo he hecho en un programa anterior).

Así que supongo que, si desea un registro multiproceso independiente de la plataforma, utilice conectores y cree un nuevo SocketHandler después de cada horquilla para que sea seguro como sugiere Vinay a continuación (esto debería funcionar en todas partes). Para mí, dado que tengo un fuerte control sobre el sistema operativo en el que se está ejecutando mi software, creo que voy a ir con un objeto global log con un FileHandler (se abre en el modo de adición y la línea está almacenada en la mayoría de los sistemas operativos). La documentación para open dice "Un buffer negativo significa usar el sistema predeterminado, que generalmente es un buffer de línea para dispositivos tty y está totalmente almacenado en el búfer para otros archivos. Si se omite, se usa el sistema predeterminado". o podría simplemente crear mi propia secuencia de registro para garantizar el almacenamiento en línea de la memoria. Y sólo para que quede claro, yo estoy bien con:

# Process A 
a_file.write("A\n") 
a_file.write("A\n") 
# Process B 
a_file.write("B\n") 

producir ...

A\n 
B\n 
A\n 

con tal de que no produce ...

AB\n 
\n 
A\n 

Vinay (o cualquier otro), lo equivocado soy yo? Házmelo saber. Gracias por más claridad/seguridad que puede proporcionar.

+0

Los hilos y los bloqueos son útiles para cosas como esta ... –

+0

Necesito procesos separados ya que los niños se están comunicando con dispositivos externos que deberían ser lo más "rápidos" posible. – daveydave400

+0

He actualizado mi respuesta. –

Respuesta

2

¿Necesito crear un nuevo objeto de registro después de cada os.fork()? ¿Qué ocurre con el objeto de registro global existente?

AFAIK el objeto de registro global permanece apuntando al mismo registrador en los procesos primarios y secundarios. Entonces no deberías necesitar crear uno nuevo. Sin embargo, creo que debe crear y agregar el SocketHandler después del fork() en monitor(), de modo que el servidor de socket tenga cuatro conexiones distintas, una para cada proceso secundario. Si no hace esto, entonces el proceso secundario bifurcado en monitor() heredará el SocketHandler y su manejador de socket de su padre, pero no estoy seguro de que se portará mal. Es probable que el comportamiento dependa del sistema operativo y puede que tengas suerte con OSX.

Al hacer las cosas como soy, ¿incluso estoy solucionando el problema que estoy tratando de evitar (varios archivos/sockets abiertos)? ¿Fallará esto y por qué fallará (me gustaría poder decir si las implementaciones similares futuras fallarán)?

no esperaría fracaso si se crea la conexión de socket con el servidor de socket después de la última fork() como he sugerido más arriba, pero no estoy seguro de que el comportamiento está bien definido en cualquier otro caso. Usted se refiere a múltiples archivos abiertos, pero no veo ninguna referencia a la apertura de archivos en su fragmento de pseudocódigo, simplemente abriendo sockets.

Además, ¿de qué manera falla el método "normal" (un log = expresión) de iniciar sesión en un archivo de múltiples procesos? ¿Aumenta un IOError/OSError? ¿O simplemente no escribe completamente los datos en el archivo?

Creo que el comportamiento no está bien definido, pero uno esperaría que los modos de falla se presentaran como mensajes de registro intercalados de diferentes procesos en el archivo, p.

Process A writes first part of its message 
Process B writes its message 
Process A writes second part of its message 

Actualización: Si utiliza un FileHandler en la forma que se describe en su comentario, las cosas no serán tan buenos, debido a la situación que he descrito arriba: Proceso A y B ambos comienzan señalando a al final del archivo (debido al modo de adición), pero luego las cosas pueden salir de sincronización porque (por ejemplo, en un multiprocesador, pero incluso potencialmente en un uniprocesador), un proceso puede (adelantarse a otro y) escribir en el manejador de archivo compartido antes otro proceso ha terminado de hacerlo.

+0

Cuando dije varios archivos quise decir si había hecho un FileHandler básico en lugar de un SocketHandler. Hablé con un compañero de trabajo y mencionó que si el registro abre un FileHandler en el modo de agregar en Linux, debería estar bien (un objeto de registro, un manejador de archivos, múltiples). ¿Pensamientos? Y la creación de SocketHandlers después de un tenedor tiene sentido. – daveydave400

+0

He actualizado mi pregunta, gracias. – daveydave400

+0

Aceptaré su respuesta debido a la creación del SocketHandler después de la bifurcación, pero todavía no estoy de acuerdo con el modo de adición (kernel debería hacer las escrituras anexas atómicas). – daveydave400

Cuestiones relacionadas