Domanda

Mantenere la GUI reattiva mentre l'applicazione esegue l'elaborazione pesante della CPU è una delle sfide di un'efficace programmazione della GUI.

Ecco una buona discussione su come farlo in wxPython. Per riassumere, ci sono 3 modi:

  1. Usa discussioni
  2. Usa wxYield
  3. Blocca il lavoro ed eseguilo nel gestore di eventi IDLE

Quale metodo tu hai trovato essere il più efficace? Anche le tecniche di altri framework (come Qt, GTK o API di Windows) sono benvenute.

È stato utile?

Soluzione

Le discussioni. Sono quello che cerco sempre perché puoi farlo in ogni quadro di cui hai bisogno.

E una volta che sei abituato al multi-threading e all'elaborazione parallela in una lingua / framework, sei bravo in tutti i framework.

Altri suggerimenti

Sicuramente discussioni. Perché? Il futuro è multi-core. Quasi ogni nuova CPU ha più di un core o se ne ha solo uno, potrebbe supportare l'hyperthreading e quindi fingere di averne più di uno. Per utilizzare efficacemente le CPU multi-core (e Intel sta pianificando di arrivare a 32 core in un futuro non molto lontano), sono necessari più thread. Se esegui tutto in un thread principale (di solito il thread dell'interfaccia utente è il thread principale), gli utenti disporranno di CPU con 8, 16 e un giorno 32 core e l'applicazione non ne utilizzerà mai più di uno, IOW funziona molto, molto più lentamente di quanto potrebbe funzionare.

In realtà se pianifichi un'applicazione al giorno d'oggi, vorrei andare via dal design classico e pensare a una relazione padrone / schiavo. L'interfaccia utente è il master, l'unica attività è interagire con l'utente. Ciò sta visualizzando i dati all'utente e raccogliendo l'input dell'utente. Ogni volta che l'app deve " elaborare dati " (anche piccole quantità e molto più importanti), crea un "task" di qualsiasi tipo, inoltra questa attività a un thread in background e fai in modo che il thread esegua l'attività, fornendo feedback all'interfaccia utente (ad es. quante percentuali ha completato o solo se l'attività è ancora in esecuzione o meno, quindi l'interfaccia utente può mostrare un " ; indicatore lavori in corso "). Se possibile, suddividere l'attività in molte attività secondarie piccole ed indipendenti ed eseguire più di un processo in background, alimentando una attività secondaria per ognuna di esse. In questo modo la tua applicazione può davvero trarre vantaggio dal multi-core e aumentare la velocità con il maggior numero di core delle CPU

In realtà aziende come Apple e Microsoft stanno già pianificando come rendere multithread le loro interfacce utente ancora più single thread. Anche con l'approccio sopra, un giorno potresti avere la situazione che l'IU è il collo di bottiglia stesso. I processi in background possono elaborare i dati molto più velocemente di quanto l'interfaccia utente possa presentarli all'utente o chiedere input all'utente. Oggi molti framework dell'interfaccia utente sono poco thread-safe, molti non thread-safe, ma questo cambierà. L'elaborazione seriale (eseguendo un'attività dopo l'altra) è un progetto morente, l'elaborazione parallela (eseguendo molte attività contemporaneamente) è il futuro. Guarda le schede grafiche. Anche la più moderna scheda NVidia ha prestazioni pietose, se si guarda alla velocità di elaborazione in MHz / GHz della sola GPU. Come mai può battere la merda delle CPU quando si tratta di calcoli 3D? Semplice: invece di calcolare un punto poligonale o un pixel di trama dopo l'altro, ne calcola molti in parallelo (in realtà un intero gruppo contemporaneamente) e in questo modo raggiunge un throughput che fa piangere ancora le CPU. Per esempio. l'ATI X1900 (per nominare anche il concorrente) ha 48 unità shader!

Penso che delayedresult sia quello che stai cercando:

http://www.wxpython.org/docs /api/wx.lib.delayedresult-module.html

Guarda la demo di wxpython per un esempio.

Discussioni o processi a seconda dell'applicazione. A volte è meglio avere la GUI come programma proprio e inviare chiamate asincrone ad altri programmi quando ha del lavoro da fare. Finirai comunque con più thread nella GUI per monitorare i risultati, ma può semplificare le cose se il lavoro svolto è complesso e non direttamente collegato alla GUI.

Discussioni - Usiamo una semplice vista a 2 livelli (GUI, logica dell'applicazione).

Il lavoro della logica dell'applicazione dovrebbe essere eseguito in un thread Python separato. Per eventi asincroni che devono propagarsi fino al livello GUI, utilizzare il sistema di eventi di wx per pubblicare eventi personalizzati. Pubblicare eventi wx è thread-safe, quindi è possibile farlo in contesti multipli.

Lavorando nell'altra direzione (eventi di input della GUI che attivano la logica dell'applicazione), ho trovato la soluzione migliore per eseguire l'home roll di un sistema di eventi personalizzato. Utilizzare il modulo Coda per disporre di un metodo thread-safe di spingere e fare scoppiare oggetti evento. Quindi, per ogni funzione membro sincrona, associarla a una versione asincrona che inserisce l'oggetto della funzione di sincronizzazione e i parametri nella coda degli eventi.

Funziona particolarmente bene se è possibile eseguire un'unica operazione a livello logico alla volta. Il vantaggio di questo modello è che la sincronizzazione è semplice: ogni funzione sincrona opera in sequenza all'interno del proprio contesto dall'inizio alla fine, senza preoccuparsi della prelazione o della resa codificata a mano. Non avrai bisogno di blocchi per proteggere le tue sezioni critiche. Alla fine della funzione, pubblica un evento nel livello della GUI che indica che l'operazione è stata completata.

Potresti ridimensionarlo per consentire l'esistenza di più thread a livello di applicazione, ma riappariranno i soliti problemi con la sincronizzazione.

modifica - Ho dimenticato di menzionare la bellezza di questo è che è possibile disaccoppiare completamente la logica dell'applicazione dal codice GUI. La modularità aiuta se si decide di utilizzare un framework diverso o utilizzare una versione della riga di comando dell'app. Per fare ciò, avrai bisogno di un dispatcher di eventi intermedio (livello applicazione - > GUI) implementato dal livello GUI.

Lavorare con Qt / C ++ per Win32.

Dividiamo le principali unità di lavoro in diversi processi. La GUI viene eseguita come un processo separato ed è in grado di comandare / ricevere dati dal "lavoratore" processi secondo necessità. Funziona bene nel mondo multi-core di oggi.

Questa risposta non si applica alla domanda del PO relativa a Python, ma è più una meta-risposta.

Il modo più semplice sono i thread. Tuttavia, non tutte le piattaforme dispongono di threading preventivo (ad esempio BREW, alcuni altri sistemi incorporati) Se possibile, semplicemente frammentare il lavoro ed eseguirlo nel gestore di eventi IDLE.

Un altro problema con l'utilizzo dei thread in BREW è che non pulisce gli oggetti dello stack C ++, quindi è troppo facile perdere la memoria se si uccide semplicemente il thread.

Uso i thread in modo che il ciclo degli eventi principali della GUI non si blocchi mai.

Per alcuni tipi di operazioni, l'uso di processi separati ha molto senso. In passato, la generazione di un processo comportava un sacco di spese generali. Con l'hardware moderno questo sovraccarico non è nemmeno un blip sullo schermo. Ciò è particolarmente vero se stai generando un processo di lunga durata.

Uno (discutibile) vantaggio è che si tratta di un modello concettuale più semplice rispetto ai thread che potrebbe portare a un codice più gestibile. Può anche semplificare il test del codice, in quanto è possibile scrivere script di test che esercitano questi processi esterni senza dover coinvolgere la GUI. Alcuni potrebbero persino sostenere che questo sia il vantaggio principale.

Nel caso di un codice su cui ho lavorato una volta, passare da thread a processi separati ha portato a una riduzione netta di oltre 5000 righe di codice, rendendo allo stesso tempo la GUI più reattiva, il codice più facile da mantenere e testare, il tutto migliorando le prestazioni complessive complessive.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top