interfaz graficas grafica descargar con como aplicaciones python user-interface wxpython

python - graficas - Mantener las GUI receptivas durante las tareas de larga ejecución



tkinter python (9)

Mantener la GUI receptiva mientras la aplicación realiza un procesamiento pesado de la CPU es uno de los desafíos de la programación efectiva de la GUI.

Aquí hay una buena discusión sobre cómo hacer esto en wxPython. Para resumir, hay 3 formas:

  1. Usar hilos
  2. Use wxYield
  3. Rompe el trabajo y hazlo en el controlador de eventos IDLE

¿Qué método ha encontrado que es el más efectivo? También son bienvenidas las técnicas de otros marcos (como Qt, GTK o API de Windows).


Definitivamente hilos. ¿Por qué? El futuro es multi-core. Casi cualquier CPU nueva tiene más de un núcleo o, si solo tiene uno, puede admitir el hyperthreading y pretender que tiene más de uno. Para hacer un uso efectivo de las CPU multinúcleo (e Intel planea llegar hasta 32 núcleos en un futuro no muy lejano), necesita múltiples hilos. Si ejecuta todo en un hilo principal (generalmente el hilo de UI es el hilo principal), los usuarios tendrán CPU con 8, 16 y un día 32 núcleos y su aplicación nunca utiliza más de uno, IOW se ejecuta mucho, mucho más lento de lo que podría correr

Actual si planifica una aplicación hoy en día, me iría del diseño clásico y pensaría en una relación amo / esclavo. Su interfaz de usuario es el maestro, su única tarea es interactuar con el usuario. Eso es mostrar datos al usuario y recopilar información del usuario. Siempre que su aplicación necesite "procesar cualquier dato" (incluso cantidades pequeñas y mucho más importantes), cree una "tarea" de cualquier tipo, reenvíe esta tarea a un hilo de fondo y haga que el hilo realice la tarea, proporcionando comentarios al IU (por ejemplo, cuántos porcentajes ha completado o solo si la tarea aún se está ejecutando o no, por lo que la IU puede mostrar un "indicador de trabajo en progreso"). Si es posible, divida la tarea en muchas subtareas pequeñas e independientes y ejecute más de un proceso de fondo, alimentando una subtarea a cada una de ellas. De esta manera, su aplicación puede beneficiarse realmente de multi-core y obtener más rápido cuanto más núcleos tengan las CPU.

En realidad, compañías como Apple y Microsoft ya están planeando cómo hacer que sus interfaces de usuario (UI) con la mayoría de las hebras únicas sean multiproceso. Incluso con el enfoque anterior, es posible que algún día tenga la situación de que la IU es el cuello de botella en sí mismo. Los procesos en segundo plano pueden procesar datos mucho más rápido de lo que la UI puede presentarle al usuario o pedirle al usuario que los ingrese. En la actualidad, muchos marcos de interfaz de usuario son poco seguros para subprocesos, muchos de ellos no son seguros para subprocesos, pero eso cambiará. El procesamiento en serie (hacer una tarea tras otra) es un diseño en extinción, el procesamiento paralelo (hacer muchas tareas a la vez) es el futuro. Solo mira los adaptadores gráficos. Incluso la tarjeta NVidia más moderna tiene un rendimiento lamentable, si se mira la velocidad de procesamiento en MHz / GHz de la GPU solo. ¿Cómo es que puede vencer a las CPU cuando se trata de cálculos en 3D? Simple: en lugar de calcular un punto de polígono o un píxel de textura tras otro, calcula muchos de ellos en paralelo (en realidad, un grupo completo al mismo tiempo) y de ese modo alcanza un rendimiento que todavía hace llorar a las CPU. ¡Por ejemplo, el ATI X1900 (para nombrar al competidor también) tiene 48 unidades de sombreado!


Esta respuesta no se aplica a la pregunta del OP con respecto a Python, sino que es más una meta respuesta.

La manera fácil es hilos. Sin embargo, no todas las plataformas tienen subprocesos preventivos (por ejemplo, BREW, algunos otros sistemas integrados) Si es posible, simplemente interrumpa el trabajo y hágalo en el controlador de eventos IDLE.

Otro problema con el uso de subprocesos en BREW es que no limpia los objetos de la pila C ++, por lo que es demasiado fácil perder memoria si simplemente se elimina el hilo.


Hilos - Usemos una vista simple de 2 capas (GUI, lógica de aplicación).

El trabajo de lógica de la aplicación debe hacerse en un hilo de Python separado. Para los eventos asincrónicos que necesitan propagarse a la capa de la GUI, use el sistema de eventos de wx para publicar eventos personalizados. La publicación de eventos wx es segura para subprocesos, por lo que podría hacerlo desde múltiples contextos.

Trabajando en la otra dirección (eventos de entrada de la GUI que desencadenan la lógica de la aplicación), he encontrado que es mejor rodar un sistema de evento personalizado. Use el módulo Queue para tener una forma segura de subprocesos para empujar y mostrar objetos de evento. Luego, para cada función miembro síncrona, vincúlela con una versión asíncrona que empuje el objeto de función de sincronización y los parámetros a la cola de eventos.

Esto funciona particularmente bien si solo se puede realizar una sola operación de nivel lógico de aplicación a la vez. El beneficio de este modelo es que la sincronización es simple: cada función síncrona funciona en su propio contexto de forma secuencial de principio a fin sin preocuparse por la anticipación o el rendimiento codificado a mano. No necesitará cerraduras para proteger sus secciones críticas. Al final de la función, publique un evento en la capa de la GUI indicando que la operación está completa.

Puede escalar esto para permitir que existan varios subprocesos a nivel de aplicación, pero volverán a aparecer las preocupaciones habituales con la sincronización.

editar - Olvidé mencionar la belleza de esto es que es posible desacoplar por completo la lógica de la aplicación del código de la GUI. La modularidad ayuda si alguna vez decide utilizar un marco diferente o si utiliza una versión de línea de comandos de la aplicación. Para hacer esto, necesitará un despachador de eventos intermedios (nivel de aplicación -> GUI) que es implementado por la capa de la GUI.


Hilos o procesos según la aplicación. A veces es mejor tener la GUI en su propio programa y simplemente enviar llamadas asincrónicas a otros programas cuando tiene trabajo por hacer. Todavía tendrá varios subprocesos en la GUI para monitorear los resultados, pero puede simplificar las cosas si el trabajo que se realiza es complejo y no está directamente conectado a la GUI.


Para algunos tipos de operaciones, usar procesos separados tiene mucho sentido. En el pasado, engendrar un proceso generaba muchos gastos generales. Con el hardware moderno, esta sobrecarga apenas es un problema en la pantalla. Esto es especialmente cierto si está generando un proceso de larga ejecución.

Una ventaja (discutible) es que es un modelo conceptual más simple que los hilos que pueden conducir a un código más fácil de mantener. También puede hacer que su código sea más fácil de probar, ya que puede escribir scripts de prueba que ejerzan estos procesos externos sin tener que involucrar a la GUI. Algunos incluso podrían argumentar que esa es la principal ventaja.

En el caso de algún código en el que trabajé una vez, el cambio de hilos a procesos separados condujo a una reducción neta de más de 5000 líneas de código mientras que al mismo tiempo hacía que la GUI fuera más receptiva, el código más fácil de mantener y probar, mientras mejoraba el rendimiento general total.


Trabajando con Qt / C ++ para Win32.

Dividimos las principales unidades de trabajo en diferentes procesos. La GUI se ejecuta como un proceso separado y puede ordenar / recibir datos de los procesos de "trabajador" según sea necesario. Funciona muy bien en el mundo multi-core de hoy.


Trapos. Son lo que siempre busco porque puedes hacerlo en todos los marcos que necesites.

Y una vez que está acostumbrado a multi-threading y procesamiento paralelo en un idioma / marco, es bueno en todos los marcos.


Utilizo hilos para que el ciclo de eventos principales de la GUI nunca se bloquee.