Python IPC con matplotlib

Descripción del Proyecto:

Conecte el progtwig “C” existente (control principal) a la GUI / Widget de Python. Para esto estoy usando un FIFO. El progtwig C está diseñado para mirar telemetría basada en cuadros.

La GUI de Python realiza dos funciones:

  1. Ejecuta / crea gráficos (probablemente creados a través de matplotlib) a través del widget GUI según lo desee el usuario (archivos .py individuales, scripts escritos por diferentes usuarios)
  2. Transfiere el número de fotogtwig a los scripts de trazado de python después de que se hayan creado para que puedan “actualizarse” ellos mismos después de recibir el número de fotogtwig del progtwig maestro.

Tengo varias preguntas: comprender los pros y los contras del multiproceso frente al multiprocesamiento que se ve aquí: multiproceso frente a subprocesamiento de Python

Consideraciones de implementación:

  1. Supongo que tener demasiados gráficos creados a través de subprocesos en una architecture basada en señales probablemente se retrasa en términos de actualización. No estoy seguro de cuándo se unirán a la CPU … la mayoría de los gráficos actualizarán algunas series de líneas, algunos pueden actualizar las imágenes. Tal vez sea lento, independientemente de la forma en que elija hacerlo independientemente del método de creación.

  2. No estoy seguro de qué procesos de apertura de 30 pitones, donde cada proceso hace una o dos gráficas con matplotlib, lo hace con una máquina o sus recursos. Veo que un solo gráfico simple de matplotlib en mi sistema tiene un RSS (memoria asignada) de 117M, por lo que no creo que un solo usuario que graficara 30 gráficos limitaría la memoria del sistema si se realiza abriendo procesos separados para cada gráfico. (16 GB, 32-core Linux Boxes con varios usuarios simultáneos)

Preguntas:

  1. ¿Debo abrir los gráficos a través de hilos o procesos y uno será menos demorado que el otro?
  2. Si uso subprocesos, ¿alguien tiene alguna idea de cuántas cifras de matplotlib se necesitarán para actualizar antes de que se retrasen en un solo subproceso?
  3. Si creo los gráficos como procesos, ¿debo usar el paquete de multiprocesamiento? ¿Supongo que esta API hace que sea sencillo comunicar el número de ttwig entre procesos?
  4. Dado que tengo multiprocesamiento disponible, probablemente sea una tontería intentar abrir procesos a través de POpen, ¿no? Supongo que este es el caso porque si lo hiciera, tendría que configurar yo mismo toda la tubería / IPC, ¿qué sería más trabajo?

Así que pude implementar este proyecto de dos maneras: con y sin multiprocesos.

  1. Tengo un proceso principal en una GUI de PyQt con un subproceso que se lee desde el canal del número de ttwig del progtwig C controlador.
  2. Cuando el usuario selecciona gráficos (.py scripts) tiene la opción de presionar el botón “ejecutar” en un lote de gráficos que los mantiene en el proceso principal. A partir de este punto, si se actualiza el marco, los gráficos se actualizarán en serie. La desaceleración comienza a ocurrir casi inmediatamente después de un puñado de plots, pero no es prohibitiva para 10 a 20 ttwigs de series de tiempo simples.
  3. Hay un botón alternativo que permite procesar con otro proceso. Pude hacer esto con POpen y una tubería con nombre o multiprocesamiento y una cola de multiprocesamiento. La forma más limpia de hacer esto fue hacer que mis otros procesos crearan los QObjects de las plots y usaran las señales de pyqt donde cada uno de los otros procesos terminaba creando una QApplications en ese proceso, pero tuve que usar ctx = mp.get_context (‘spawn’ ) en Linux porque, de forma predeterminada, Linux usa una bifurcación y cuando creé QApplication cree que QApplication ya se estaba ejecutando en el proceso principal. Esta fue la única forma en que pude obtener un comportamiento de procesamiento múltiple predecible en el que todas las gráficas matplotlib se actualizarían en el proceso alternativo.

Leí que matplotlib no es seguro para subprocesos en la web, sin embargo, con las ranuras pyqt que emiten desde los subprocesos esperando que la cola lea esto parece estar bien.

Elegí la implementación para dar al usuario la flexibilidad para abrir plots en el mismo proceso o lotes de plots en otro proceso en lugar de cantidades predeterminadas de plots por proceso, pensando que podría haber ciertas plots con actualizaciones complejas que podrían crearse y que merecerían Su propio proceso y podría ser seleccionado como tal. Esto también fue menos desperdicio que un gráfico por proceso para gráficos simples a un mínimo de 100 MB por proceso con solo 3 MB o más de memoria requerida por cada gráfico adicional en el mismo proceso.

Un último detalle fue que el usuario cambia el marco potencialmente muy rápidamente. Hice leer el proceso de recepción y vaciar la cola en un subproceso de daemon no bloqueante y capturar solo la información más reciente. Una vez que se envió una señal para actualizar las plots, el bucle de actualización de la ttwig arrebató un locking de subproceso y el daemon de lectura nuevamente puede emitir actualizaciones después de que el método de actualización liberó el locking de la hebra.

Algunos ejemplos de código de la idea básica de la implementación: https://stackoverflow.com/a/49226785/8209352