2011-02-12 20 views
5

Pregunta:GEvent y multiprocesamiento juntos para comunicarse con un subproceso

¿Puedo usar el módulo de multiprocesamiento junto con GEvent en Windows de una manera eficiente?

Escenario:

Tengo una aplicación basada en Python GEvent haciendo E/S asíncrona en Windows. La aplicación está principalmente vinculada a E/S, pero también hay picos de mayor carga de CPU. Esta aplicación necesitaría controlar una aplicación de consola a través de stdin y stdout. No puedo modificar esta aplicación de consola y el usuario podrá usar la suya propia, solo se corrige el protocolo de comunicación basado en texto (línea).

Tengo una implementación en funcionamiento que usa subprocesos y subprocesos, pero prefiero mover todo el subproceso basado en el código de comunicación junto con esos subprocesos en un proceso separado para volver la aplicación principal a un subproceso único. Planeo usar el módulo de multiprocesamiento para esto.

lectura previa:

He estado buscando en la web mucho y leo algo de código fuente, así que sé que el módulo de multiprocesamiento está utilizando una aplicación de tubería basado en canalizaciones con nombre en Windows. Se usaría un par de objetos multiprocessing.queue.Queue para comunicarse con el segundo proceso de Python. Estas colas se basan en esa implementación de Pipe, p. el IPC se haría a través de tuberías con nombre.

La pregunta clave es si llamar al método get de la cola entrante bloquearía o no el bucle principal de gevent. Hay un tiempo de espera para ese método, por lo que podría hacer un ciclo con un pequeño tiempo de espera, pero esa no es una buena solución, ya que aún bloquearía gevent por períodos de tiempo pequeños que dañaran su baja latencia de E/S.

También estoy abierto a sugerencias sobre cómo eludir todo el problema del uso de tuberías en Windows, que se sabe que es difícil ya veces frágil. No estoy seguro de si la IPC basada en memoria compartida es posible en Windows o no. Tal vez podría envolver la aplicación de la consola de una manera que permita la comunicación con el proceso secundario utilizando sockets de red, que se sabe que funciona bien con gevent.

Por favor, no cuestione mi caso de uso principal, si es posible. Gracias.

+0

Encontré un módulo adecuado para leer y escribir de forma asíncrona las canalizaciones de subprocesos tanto en Windows como en UNIX. Se podría integrar con el ciclo de eventos de gevent para obtener una solución bastante genérica: http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/ – fviktor

Respuesta

1

El método get de Queue es realmente un bloqueo. Usarlo con tiempo de espera podría resolver su problema, pero definitivamente no será la solución más limpia y, lo que es más importante, introducirá latencia adicional sin una buena razón. Incluso si no estuviera bloqueando, tampoco será una buena solución. Solo porque el propio no bloqueo no es suficiente, la buena llamada/API asíncrona se integrará sin problemas en el marco de E/S en uso. Sé ese gevent para Python, libevent para C o Boost ASIO para C++.

La solución más fácil sería usar E/S simples al generar las aplicaciones de la consola y adjuntarlas a las descripciones de entrada y salida de la consola. Hay dos factores principales a tener en cuenta:

  • Será extremadamente fácil para sus clientes escribir aplicaciones cliente. No tendrán que trabajar con ningún tipo de IPC, zócalo u otro código, lo que podría ser algo muy difícil para muchos. Con este enfoque, la aplicación solo leerá de stdin y escribirá en stdout.
  • Será extremadamente fácil probar aplicaciones de consola utilizando este enfoque, ya que puede iniciarlas manualmente, ingresar texto en la consola y ver resultados.
  • Gevent es una opción perfecta para lectura/escritura asíncrona aquí.

Sin embargo, la desventaja es que tendrá que iniciar esta aplicación, no habrá soporte para la comunicación concurrente con ella, y no habrá soporte para la comunicación a través de la red. Incluso hay un good example for starters.

Para que sea sencillo pero más flexible, puede usar sockets TCP/IP. Si el cliente y el servidor se ejecutan en la misma máquina. Además, un buen sistema operativo usará IPC como implementación subyacente, por lo que será rápido. Y, si te preocupa el rendimiento de este caso, probablemente no deberías usar Python en absoluto y mirar otras tecnologías.

Solución de fantasías uniformes: use ZeroC ICE. Es una tecnología muy moderna que permite una comunicación entre procesos casi perfecta. Es un asesino de CORBA, muy fácil de usar. Es muy utilizado por muchos, ha demostrado ser el más rápido en su clase y roca estable. La belleza de esta solución es que puede integrar programas en muchos idiomas diferentes, como Python, Java, C++, etc. Pero esto requerirá algo de tiempo para familiarizarse con un concepto. Si decides ir de esta manera, solo pasa un día leyendo la documentación básica.

Espero que ayude. ¡Buena suerte!

+0

Gracias por responder en detalle. El problema con el ejemplo de gevent processes.py es que implementa solo un único paso de comunicación. Estamos utilizando un trabajador que puede enviar datos en cualquier momento y podemos enviarle comandos mientras tanto, como el comando de detención. Pero no terminará el subproceso, debería seguir siendo utilizable. Sin embargo, intentaré integrar los dos bucles. Puede que no ayude en Windows, pero vale la pena intentarlo. Usar TCP/IP es otra opción en la que estaba pensando, pero necesitaría una capa de envoltura, lo que complica las cosas y hace que la solución tenga mucho peso. Echaré un vistazo a ZeroC ICE. – fviktor

+0

@fviktor: De nada. Puede enviar datos en cualquier momento usando async I/O. Lo único que tendrá que garantizar es que no realizará múltiples escrituras en paralelo. El hilo del escritor dedicado y algunas colas ayudan en este caso. –

0

Tu pregunta ya es bastante antigua. Sin embargo, me gustaría recomendar http://gehrcke.de/gipc que, creo, abordaría el desafío descrito de una manera muy directa. Básicamente, le permite integrar procesos secundarios basados ​​en multiprocesamiento en cualquier lugar de su aplicación (también en Windows). La interacción con objetos Process (como llamar al join()) es gevent-cooperative. A través de su gestión de tuberías, permite cooperativamente bloquear la comunicación entre procesos. Sin embargo, en Windows, IPC actualmente es mucho menos eficiente que en sistemas que cumplen con POSIX (ya que la E/S sin bloqueo se imita a través de un grupo de subprocesos). Dependiendo del volumen de mensajes IPC de su aplicación, esto podría o no ser importante.

Cuestiones relacionadas